brintos

brintos / llvm-project-archived public Read only

0
0
Text · 206.4 KiB · 7b6ec4d Raw
6270 lines · cpp
1//===- AsmParser.cpp - Parser for Assembly Files --------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This class implements the parser for assembly files.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ADT/APFloat.h"14#include "llvm/ADT/APInt.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/BitVector.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/SmallString.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/ADT/StringMap.h"22#include "llvm/ADT/StringRef.h"23#include "llvm/ADT/StringSwitch.h"24#include "llvm/ADT/Twine.h"25#include "llvm/MC/MCAsmInfo.h"26#include "llvm/MC/MCCodeView.h"27#include "llvm/MC/MCContext.h"28#include "llvm/MC/MCDirectives.h"29#include "llvm/MC/MCExpr.h"30#include "llvm/MC/MCInstPrinter.h"31#include "llvm/MC/MCInstrDesc.h"32#include "llvm/MC/MCInstrInfo.h"33#include "llvm/MC/MCParser/AsmCond.h"34#include "llvm/MC/MCParser/AsmLexer.h"35#include "llvm/MC/MCParser/MCAsmParser.h"36#include "llvm/MC/MCParser/MCAsmParserExtension.h"37#include "llvm/MC/MCParser/MCParsedAsmOperand.h"38#include "llvm/MC/MCParser/MCTargetAsmParser.h"39#include "llvm/MC/MCSection.h"40#include "llvm/MC/MCStreamer.h"41#include "llvm/MC/MCSubtargetInfo.h"42#include "llvm/MC/MCSymbolCOFF.h"43#include "llvm/MC/MCTargetOptions.h"44#include "llvm/Support/Casting.h"45#include "llvm/Support/CommandLine.h"46#include "llvm/Support/ErrorHandling.h"47#include "llvm/Support/Format.h"48#include "llvm/Support/MD5.h"49#include "llvm/Support/MathExtras.h"50#include "llvm/Support/MemoryBuffer.h"51#include "llvm/Support/Path.h"52#include "llvm/Support/SMLoc.h"53#include "llvm/Support/SourceMgr.h"54#include "llvm/Support/raw_ostream.h"55#include <algorithm>56#include <cassert>57#include <climits>58#include <cstddef>59#include <cstdint>60#include <ctime>61#include <deque>62#include <memory>63#include <optional>64#include <sstream>65#include <string>66#include <tuple>67#include <utility>68#include <vector>69 70using namespace llvm;71 72namespace {73 74/// Helper types for tracking macro definitions.75typedef std::vector<AsmToken> MCAsmMacroArgument;76typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;77 78/// Helper class for storing information about an active macro instantiation.79struct MacroInstantiation {80  /// The location of the instantiation.81  SMLoc InstantiationLoc;82 83  /// The buffer where parsing should resume upon instantiation completion.84  unsigned ExitBuffer;85 86  /// The location where parsing should resume upon instantiation completion.87  SMLoc ExitLoc;88 89  /// The depth of TheCondStack at the start of the instantiation.90  size_t CondStackDepth;91};92 93struct ParseStatementInfo {94  /// The parsed operands from the last parsed statement.95  SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands;96 97  /// The opcode from the last parsed instruction.98  unsigned Opcode = ~0U;99 100  /// Was there an error parsing the inline assembly?101  bool ParseError = false;102 103  /// The value associated with a macro exit.104  std::optional<std::string> ExitValue;105 106  SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr;107 108  ParseStatementInfo() = delete;109  ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)110      : AsmRewrites(rewrites) {}111};112 113enum FieldType {114  FT_INTEGRAL, // Initializer: integer expression, stored as an MCExpr.115  FT_REAL,     // Initializer: real number, stored as an APInt.116  FT_STRUCT    // Initializer: struct initializer, stored recursively.117};118 119struct FieldInfo;120struct StructInfo {121  StringRef Name;122  bool IsUnion = false;123  bool Initializable = true;124  unsigned Alignment = 0;125  unsigned AlignmentSize = 0;126  unsigned NextOffset = 0;127  unsigned Size = 0;128  std::vector<FieldInfo> Fields;129  StringMap<size_t> FieldsByName;130 131  FieldInfo &addField(StringRef FieldName, FieldType FT,132                      unsigned FieldAlignmentSize);133 134  StructInfo() = default;135  StructInfo(StringRef StructName, bool Union, unsigned AlignmentValue);136};137 138// FIXME: This should probably use a class hierarchy, raw pointers between the139// objects, and dynamic type resolution instead of a union. On the other hand,140// ownership then becomes much more complicated; the obvious thing would be to141// use BumpPtrAllocator, but the lack of a destructor makes that messy.142 143struct StructInitializer;144struct IntFieldInfo {145  SmallVector<const MCExpr *, 1> Values;146 147  IntFieldInfo() = default;148  IntFieldInfo(const SmallVector<const MCExpr *, 1> &V) { Values = V; }149  IntFieldInfo(SmallVector<const MCExpr *, 1> &&V) { Values = std::move(V); }150};151struct RealFieldInfo {152  SmallVector<APInt, 1> AsIntValues;153 154  RealFieldInfo() = default;155  RealFieldInfo(const SmallVector<APInt, 1> &V) { AsIntValues = V; }156  RealFieldInfo(SmallVector<APInt, 1> &&V) { AsIntValues = std::move(V); }157};158struct StructFieldInfo {159  std::vector<StructInitializer> Initializers;160  StructInfo Structure;161 162  StructFieldInfo() = default;163  StructFieldInfo(std::vector<StructInitializer> V, StructInfo S);164};165 166class FieldInitializer {167public:168  FieldType FT;169  union {170    IntFieldInfo IntInfo;171    RealFieldInfo RealInfo;172    StructFieldInfo StructInfo;173  };174 175  ~FieldInitializer();176  FieldInitializer(FieldType FT);177 178  FieldInitializer(SmallVector<const MCExpr *, 1> &&Values);179  FieldInitializer(SmallVector<APInt, 1> &&AsIntValues);180  FieldInitializer(std::vector<StructInitializer> &&Initializers,181                   struct StructInfo Structure);182 183  FieldInitializer(const FieldInitializer &Initializer);184  FieldInitializer(FieldInitializer &&Initializer);185 186  FieldInitializer &operator=(const FieldInitializer &Initializer);187  FieldInitializer &operator=(FieldInitializer &&Initializer);188};189 190struct StructInitializer {191  std::vector<FieldInitializer> FieldInitializers;192};193 194struct FieldInfo {195  // Offset of the field within the containing STRUCT.196  unsigned Offset = 0;197 198  // Total size of the field (= LengthOf * Type).199  unsigned SizeOf = 0;200 201  // Number of elements in the field (1 if scalar, >1 if an array).202  unsigned LengthOf = 0;203 204  // Size of a single entry in this field, in bytes ("type" in MASM standards).205  unsigned Type = 0;206 207  FieldInitializer Contents;208 209  FieldInfo(FieldType FT) : Contents(FT) {}210};211 212StructFieldInfo::StructFieldInfo(std::vector<StructInitializer> V,213                                 StructInfo S) {214  Initializers = std::move(V);215  Structure = S;216}217 218StructInfo::StructInfo(StringRef StructName, bool Union,219                       unsigned AlignmentValue)220    : Name(StructName), IsUnion(Union), Alignment(AlignmentValue) {}221 222FieldInfo &StructInfo::addField(StringRef FieldName, FieldType FT,223                                unsigned FieldAlignmentSize) {224  if (!FieldName.empty())225    FieldsByName[FieldName.lower()] = Fields.size();226  Fields.emplace_back(FT);227  FieldInfo &Field = Fields.back();228  Field.Offset =229      llvm::alignTo(NextOffset, std::min(Alignment, FieldAlignmentSize));230  if (!IsUnion) {231    NextOffset = std::max(NextOffset, Field.Offset);232  }233  AlignmentSize = std::max(AlignmentSize, FieldAlignmentSize);234  return Field;235}236 237FieldInitializer::~FieldInitializer() {238  switch (FT) {239  case FT_INTEGRAL:240    IntInfo.~IntFieldInfo();241    break;242  case FT_REAL:243    RealInfo.~RealFieldInfo();244    break;245  case FT_STRUCT:246    StructInfo.~StructFieldInfo();247    break;248  }249}250 251FieldInitializer::FieldInitializer(FieldType FT) : FT(FT) {252  switch (FT) {253  case FT_INTEGRAL:254    new (&IntInfo) IntFieldInfo();255    break;256  case FT_REAL:257    new (&RealInfo) RealFieldInfo();258    break;259  case FT_STRUCT:260    new (&StructInfo) StructFieldInfo();261    break;262  }263}264 265FieldInitializer::FieldInitializer(SmallVector<const MCExpr *, 1> &&Values)266    : FT(FT_INTEGRAL) {267  new (&IntInfo) IntFieldInfo(std::move(Values));268}269 270FieldInitializer::FieldInitializer(SmallVector<APInt, 1> &&AsIntValues)271    : FT(FT_REAL) {272  new (&RealInfo) RealFieldInfo(std::move(AsIntValues));273}274 275FieldInitializer::FieldInitializer(276    std::vector<StructInitializer> &&Initializers, struct StructInfo Structure)277    : FT(FT_STRUCT) {278  new (&StructInfo) StructFieldInfo(std::move(Initializers), Structure);279}280 281FieldInitializer::FieldInitializer(const FieldInitializer &Initializer)282    : FT(Initializer.FT) {283  switch (FT) {284  case FT_INTEGRAL:285    new (&IntInfo) IntFieldInfo(Initializer.IntInfo);286    break;287  case FT_REAL:288    new (&RealInfo) RealFieldInfo(Initializer.RealInfo);289    break;290  case FT_STRUCT:291    new (&StructInfo) StructFieldInfo(Initializer.StructInfo);292    break;293  }294}295 296FieldInitializer::FieldInitializer(FieldInitializer &&Initializer)297    : FT(Initializer.FT) {298  switch (FT) {299  case FT_INTEGRAL:300    new (&IntInfo) IntFieldInfo(Initializer.IntInfo);301    break;302  case FT_REAL:303    new (&RealInfo) RealFieldInfo(Initializer.RealInfo);304    break;305  case FT_STRUCT:306    new (&StructInfo) StructFieldInfo(Initializer.StructInfo);307    break;308  }309}310 311FieldInitializer &312FieldInitializer::operator=(const FieldInitializer &Initializer) {313  if (FT != Initializer.FT) {314    switch (FT) {315    case FT_INTEGRAL:316      IntInfo.~IntFieldInfo();317      break;318    case FT_REAL:319      RealInfo.~RealFieldInfo();320      break;321    case FT_STRUCT:322      StructInfo.~StructFieldInfo();323      break;324    }325  }326  FT = Initializer.FT;327  switch (FT) {328  case FT_INTEGRAL:329    IntInfo = Initializer.IntInfo;330    break;331  case FT_REAL:332    RealInfo = Initializer.RealInfo;333    break;334  case FT_STRUCT:335    StructInfo = Initializer.StructInfo;336    break;337  }338  return *this;339}340 341FieldInitializer &FieldInitializer::operator=(FieldInitializer &&Initializer) {342  if (FT != Initializer.FT) {343    switch (FT) {344    case FT_INTEGRAL:345      IntInfo.~IntFieldInfo();346      break;347    case FT_REAL:348      RealInfo.~RealFieldInfo();349      break;350    case FT_STRUCT:351      StructInfo.~StructFieldInfo();352      break;353    }354  }355  FT = Initializer.FT;356  switch (FT) {357  case FT_INTEGRAL:358    IntInfo = Initializer.IntInfo;359    break;360  case FT_REAL:361    RealInfo = Initializer.RealInfo;362    break;363  case FT_STRUCT:364    StructInfo = Initializer.StructInfo;365    break;366  }367  return *this;368}369 370/// The concrete assembly parser instance.371// Note that this is a full MCAsmParser, not an MCAsmParserExtension!372// It's a peer of AsmParser, not of COFFAsmParser, WasmAsmParser, etc.373class MasmParser : public MCAsmParser {374private:375  SourceMgr::DiagHandlerTy SavedDiagHandler;376  void *SavedDiagContext;377  std::unique_ptr<MCAsmParserExtension> PlatformParser;378 379  /// This is the current buffer index we're lexing from as managed by the380  /// SourceMgr object.381  unsigned CurBuffer;382 383  /// time of assembly384  struct tm TM;385 386  BitVector EndStatementAtEOFStack;387 388  AsmCond TheCondState;389  std::vector<AsmCond> TheCondStack;390 391  /// maps directive names to handler methods in parser392  /// extensions. Extensions register themselves in this map by calling393  /// addDirectiveHandler.394  StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;395 396  /// maps assembly-time variable names to variables.397  struct Variable {398    enum RedefinableKind { NOT_REDEFINABLE, WARN_ON_REDEFINITION, REDEFINABLE };399 400    StringRef Name;401    RedefinableKind Redefinable = REDEFINABLE;402    bool IsText = false;403    std::string TextValue;404  };405  StringMap<Variable> Variables;406 407  /// Stack of active struct definitions.408  SmallVector<StructInfo, 1> StructInProgress;409 410  /// Maps struct tags to struct definitions.411  StringMap<StructInfo> Structs;412 413  /// Maps data location names to types.414  StringMap<AsmTypeInfo> KnownType;415 416  /// Stack of active macro instantiations.417  std::vector<MacroInstantiation*> ActiveMacros;418 419  /// List of bodies of anonymous macros.420  std::deque<MCAsmMacro> MacroLikeBodies;421 422  /// Keeps track of how many .macro's have been instantiated.423  unsigned NumOfMacroInstantiations;424 425  /// The values from the last parsed cpp hash file line comment if any.426  struct CppHashInfoTy {427    StringRef Filename;428    int64_t LineNumber;429    SMLoc Loc;430    unsigned Buf;431    CppHashInfoTy() : LineNumber(0), Buf(0) {}432  };433  CppHashInfoTy CppHashInfo;434 435  /// The filename from the first cpp hash file line comment, if any.436  StringRef FirstCppHashFilename;437 438  /// List of forward directional labels for diagnosis at the end.439  SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels;440 441  /// AssemblerDialect. ~OU means unset value and use value provided by MAI.442  /// Defaults to 1U, meaning Intel.443  unsigned AssemblerDialect = 1U;444 445  /// Are we parsing ms-style inline assembly?446  bool ParsingMSInlineAsm = false;447 448  // Current <...> expression depth.449  unsigned AngleBracketDepth = 0U;450 451  // Number of locals defined.452  uint16_t LocalCounter = 0;453 454public:455  MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,456             const MCAsmInfo &MAI, struct tm TM, unsigned CB = 0);457  MasmParser(const MasmParser &) = delete;458  MasmParser &operator=(const MasmParser &) = delete;459  ~MasmParser() override;460 461  bool Run(bool NoInitialTextSection, bool NoFinalize = false) override;462 463  void addDirectiveHandler(StringRef Directive,464                           ExtensionDirectiveHandler Handler) override {465    ExtensionDirectiveMap[Directive] = Handler;466    DirectiveKindMap.try_emplace(Directive, DK_HANDLER_DIRECTIVE);467  }468 469  void addAliasForDirective(StringRef Directive, StringRef Alias) override {470    DirectiveKindMap[Directive] = DirectiveKindMap[Alias];471  }472 473  /// @name MCAsmParser Interface474  /// {475 476  unsigned getAssemblerDialect() override {477    if (AssemblerDialect == ~0U)478      return MAI.getAssemblerDialect();479    else480      return AssemblerDialect;481  }482  void setAssemblerDialect(unsigned i) override {483    AssemblerDialect = i;484  }485 486  void Note(SMLoc L, const Twine &Msg, SMRange Range = {}) override;487  bool Warning(SMLoc L, const Twine &Msg, SMRange Range = {}) override;488  bool printError(SMLoc L, const Twine &Msg, SMRange Range = {}) override;489 490  enum ExpandKind { ExpandMacros, DoNotExpandMacros };491  const AsmToken &Lex(ExpandKind ExpandNextToken);492  const AsmToken &Lex() override { return Lex(ExpandMacros); }493 494  void setParsingMSInlineAsm(bool V) override {495    ParsingMSInlineAsm = V;496    // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and497    // hex integer literals.498    Lexer.setLexMasmIntegers(V);499  }500  bool isParsingMSInlineAsm() override { return ParsingMSInlineAsm; }501 502  bool isParsingMasm() const override { return true; }503 504  bool defineMacro(StringRef Name, StringRef Value) override;505 506  bool lookUpField(StringRef Name, AsmFieldInfo &Info) const override;507  bool lookUpField(StringRef Base, StringRef Member,508                   AsmFieldInfo &Info) const override;509 510  bool lookUpType(StringRef Name, AsmTypeInfo &Info) const override;511 512  bool parseMSInlineAsm(std::string &AsmString, unsigned &NumOutputs,513                        unsigned &NumInputs,514                        SmallVectorImpl<std::pair<void *, bool>> &OpDecls,515                        SmallVectorImpl<std::string> &Constraints,516                        SmallVectorImpl<std::string> &Clobbers,517                        const MCInstrInfo *MII, MCInstPrinter *IP,518                        MCAsmParserSemaCallback &SI) override;519 520  bool parseExpression(const MCExpr *&Res);521  bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;522  bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,523                        AsmTypeInfo *TypeInfo) override;524  bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override;525  bool parseAbsoluteExpression(int64_t &Res) override;526 527  /// Parse a floating point expression using the float \p Semantics528  /// and set \p Res to the value.529  bool parseRealValue(const fltSemantics &Semantics, APInt &Res);530 531  /// Parse an identifier or string (as a quoted identifier)532  /// and set \p Res to the identifier contents.533  enum IdentifierPositionKind { StandardPosition, StartOfStatement };534  bool parseIdentifier(StringRef &Res, IdentifierPositionKind Position);535  bool parseIdentifier(StringRef &Res) override {536    return parseIdentifier(Res, StandardPosition);537  }538  void eatToEndOfStatement() override;539 540  bool checkForValidSection() override;541 542  /// }543 544private:545  bool expandMacros();546  const AsmToken peekTok(bool ShouldSkipSpace = true);547 548  bool parseStatement(ParseStatementInfo &Info,549                      MCAsmParserSemaCallback *SI);550  bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites);551  bool parseCppHashLineFilenameComment(SMLoc L);552 553  bool expandMacro(raw_svector_ostream &OS, StringRef Body,554                   ArrayRef<MCAsmMacroParameter> Parameters,555                   ArrayRef<MCAsmMacroArgument> A,556                   const std::vector<std::string> &Locals, SMLoc L);557 558  /// Are we inside a macro instantiation?559  bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}560 561  /// Handle entry to macro instantiation.562  ///563  /// \param M The macro.564  /// \param NameLoc Instantiation location.565  bool handleMacroEntry(566      const MCAsmMacro *M, SMLoc NameLoc,567      AsmToken::TokenKind ArgumentEndTok = AsmToken::EndOfStatement);568 569  /// Handle invocation of macro function.570  ///571  /// \param M The macro.572  /// \param NameLoc Invocation location.573  bool handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc);574 575  /// Handle exit from macro instantiation.576  void handleMacroExit();577 578  /// Extract AsmTokens for a macro argument.579  bool580  parseMacroArgument(const MCAsmMacroParameter *MP, MCAsmMacroArgument &MA,581                     AsmToken::TokenKind EndTok = AsmToken::EndOfStatement);582 583  /// Parse all macro arguments for a given macro.584  bool585  parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A,586                      AsmToken::TokenKind EndTok = AsmToken::EndOfStatement);587 588  void printMacroInstantiations();589 590  bool expandStatement(SMLoc Loc);591 592  void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg,593                    SMRange Range = {}) const {594    ArrayRef<SMRange> Ranges(Range);595    SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);596  }597  static void DiagHandler(const SMDiagnostic &Diag, void *Context);598 599  bool lookUpField(const StructInfo &Structure, StringRef Member,600                   AsmFieldInfo &Info) const;601 602  /// Enter the specified file. This returns true on failure.603  bool enterIncludeFile(const std::string &Filename);604 605  /// Reset the current lexer position to that given by \p Loc. The606  /// current token is not set; clients should ensure Lex() is called607  /// subsequently.608  ///609  /// \param InBuffer If not 0, should be the known buffer id that contains the610  /// location.611  void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0,612                 bool EndStatementAtEOF = true);613 614  /// Parse up to a token of kind \p EndTok and return the contents from the615  /// current token up to (but not including) this token; the current token on616  /// exit will be either this kind or EOF. Reads through instantiated macro617  /// functions and text macros.618  SmallVector<StringRef, 1> parseStringRefsTo(AsmToken::TokenKind EndTok);619  std::string parseStringTo(AsmToken::TokenKind EndTok);620 621  /// Parse up to the end of statement and return the contents from the current622  /// token until the end of the statement; the current token on exit will be623  /// either the EndOfStatement or EOF.624  StringRef parseStringToEndOfStatement() override;625 626  bool parseTextItem(std::string &Data);627 628  unsigned getBinOpPrecedence(AsmToken::TokenKind K,629                              MCBinaryExpr::Opcode &Kind);630 631  bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc);632  bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);633  bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);634 635  // Generic (target and platform independent) directive parsing.636  enum DirectiveKind {637    DK_NO_DIRECTIVE, // Placeholder638    DK_HANDLER_DIRECTIVE,639    DK_ASSIGN,640    DK_EQU,641    DK_TEXTEQU,642    DK_ASCII,643    DK_ASCIZ,644    DK_STRING,645    DK_BYTE,646    DK_SBYTE,647    DK_WORD,648    DK_SWORD,649    DK_DWORD,650    DK_SDWORD,651    DK_FWORD,652    DK_QWORD,653    DK_SQWORD,654    DK_DB,655    DK_DD,656    DK_DF,657    DK_DQ,658    DK_DW,659    DK_REAL4,660    DK_REAL8,661    DK_REAL10,662    DK_ALIGN,663    DK_EVEN,664    DK_ORG,665    DK_ENDR,666    DK_EXTERN,667    DK_PUBLIC,668    DK_COMM,669    DK_COMMENT,670    DK_INCLUDE,671    DK_REPEAT,672    DK_WHILE,673    DK_FOR,674    DK_FORC,675    DK_IF,676    DK_IFE,677    DK_IFB,678    DK_IFNB,679    DK_IFDEF,680    DK_IFNDEF,681    DK_IFDIF,682    DK_IFDIFI,683    DK_IFIDN,684    DK_IFIDNI,685    DK_ELSEIF,686    DK_ELSEIFE,687    DK_ELSEIFB,688    DK_ELSEIFNB,689    DK_ELSEIFDEF,690    DK_ELSEIFNDEF,691    DK_ELSEIFDIF,692    DK_ELSEIFDIFI,693    DK_ELSEIFIDN,694    DK_ELSEIFIDNI,695    DK_ELSE,696    DK_ENDIF,697 698    DK_MACRO,699    DK_EXITM,700    DK_ENDM,701    DK_PURGE,702    DK_ERR,703    DK_ERRB,704    DK_ERRNB,705    DK_ERRDEF,706    DK_ERRNDEF,707    DK_ERRDIF,708    DK_ERRDIFI,709    DK_ERRIDN,710    DK_ERRIDNI,711    DK_ERRE,712    DK_ERRNZ,713    DK_ECHO,714    DK_STRUCT,715    DK_UNION,716    DK_ENDS,717    DK_END,718    DK_PUSHFRAME,719    DK_PUSHREG,720    DK_SAVEREG,721    DK_SAVEXMM128,722    DK_SETFRAME,723    DK_RADIX,724  };725 726  /// Maps directive name --> DirectiveKind enum, for directives parsed by this727  /// class.728  StringMap<DirectiveKind> DirectiveKindMap;729 730  bool isMacroLikeDirective();731 732  // Generic (target and platform independent) directive parsing.733  enum BuiltinSymbol {734    BI_NO_SYMBOL, // Placeholder735    BI_DATE,736    BI_TIME,737    BI_VERSION,738    BI_FILECUR,739    BI_FILENAME,740    BI_LINE,741    BI_CURSEG,742    BI_CPU,743    BI_INTERFACE,744    BI_CODE,745    BI_DATA,746    BI_FARDATA,747    BI_WORDSIZE,748    BI_CODESIZE,749    BI_DATASIZE,750    BI_MODEL,751    BI_STACK,752  };753 754  /// Maps builtin name --> BuiltinSymbol enum, for builtins handled by this755  /// class.756  StringMap<BuiltinSymbol> BuiltinSymbolMap;757 758  const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc);759 760  std::optional<std::string> evaluateBuiltinTextMacro(BuiltinSymbol Symbol,761                                                      SMLoc StartLoc);762 763  // Generic (target and platform independent) directive parsing.764  enum BuiltinFunction {765    BI_NO_FUNCTION, // Placeholder766    BI_CATSTR,767  };768 769  /// Maps builtin name --> BuiltinFunction enum, for builtins handled by this770  /// class.771  StringMap<BuiltinFunction> BuiltinFunctionMap;772 773  bool evaluateBuiltinMacroFunction(BuiltinFunction Function, StringRef Name,774                                    std::string &Res);775 776  // ".ascii", ".asciz", ".string"777  bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);778 779  // "byte", "word", ...780  bool emitIntValue(const MCExpr *Value, unsigned Size);781  bool parseScalarInitializer(unsigned Size,782                              SmallVectorImpl<const MCExpr *> &Values,783                              unsigned StringPadLength = 0);784  bool parseScalarInstList(785      unsigned Size, SmallVectorImpl<const MCExpr *> &Values,786      const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);787  bool emitIntegralValues(unsigned Size, unsigned *Count = nullptr);788  bool addIntegralField(StringRef Name, unsigned Size);789  bool parseDirectiveValue(StringRef IDVal, unsigned Size);790  bool parseDirectiveNamedValue(StringRef TypeName, unsigned Size,791                                StringRef Name, SMLoc NameLoc);792 793  // "real4", "real8", "real10"794  bool emitRealValues(const fltSemantics &Semantics, unsigned *Count = nullptr);795  bool addRealField(StringRef Name, const fltSemantics &Semantics, size_t Size);796  bool parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics,797                               size_t Size);798  bool parseRealInstList(799      const fltSemantics &Semantics, SmallVectorImpl<APInt> &Values,800      const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);801  bool parseDirectiveNamedRealValue(StringRef TypeName,802                                    const fltSemantics &Semantics,803                                    unsigned Size, StringRef Name,804                                    SMLoc NameLoc);805 806  bool parseOptionalAngleBracketOpen();807  bool parseAngleBracketClose(const Twine &Msg = "expected '>'");808 809  bool parseFieldInitializer(const FieldInfo &Field,810                             FieldInitializer &Initializer);811  bool parseFieldInitializer(const FieldInfo &Field,812                             const IntFieldInfo &Contents,813                             FieldInitializer &Initializer);814  bool parseFieldInitializer(const FieldInfo &Field,815                             const RealFieldInfo &Contents,816                             FieldInitializer &Initializer);817  bool parseFieldInitializer(const FieldInfo &Field,818                             const StructFieldInfo &Contents,819                             FieldInitializer &Initializer);820 821  bool parseStructInitializer(const StructInfo &Structure,822                              StructInitializer &Initializer);823  bool parseStructInstList(824      const StructInfo &Structure, std::vector<StructInitializer> &Initializers,825      const AsmToken::TokenKind EndToken = AsmToken::EndOfStatement);826 827  bool emitFieldValue(const FieldInfo &Field);828  bool emitFieldValue(const FieldInfo &Field, const IntFieldInfo &Contents);829  bool emitFieldValue(const FieldInfo &Field, const RealFieldInfo &Contents);830  bool emitFieldValue(const FieldInfo &Field, const StructFieldInfo &Contents);831 832  bool emitFieldInitializer(const FieldInfo &Field,833                            const FieldInitializer &Initializer);834  bool emitFieldInitializer(const FieldInfo &Field,835                            const IntFieldInfo &Contents,836                            const IntFieldInfo &Initializer);837  bool emitFieldInitializer(const FieldInfo &Field,838                            const RealFieldInfo &Contents,839                            const RealFieldInfo &Initializer);840  bool emitFieldInitializer(const FieldInfo &Field,841                            const StructFieldInfo &Contents,842                            const StructFieldInfo &Initializer);843 844  bool emitStructInitializer(const StructInfo &Structure,845                             const StructInitializer &Initializer);846 847  // User-defined types (structs, unions):848  bool emitStructValues(const StructInfo &Structure, unsigned *Count = nullptr);849  bool addStructField(StringRef Name, const StructInfo &Structure);850  bool parseDirectiveStructValue(const StructInfo &Structure,851                                 StringRef Directive, SMLoc DirLoc);852  bool parseDirectiveNamedStructValue(const StructInfo &Structure,853                                      StringRef Directive, SMLoc DirLoc,854                                      StringRef Name);855 856  // "=", "equ", "textequ"857  bool parseDirectiveEquate(StringRef IDVal, StringRef Name,858                            DirectiveKind DirKind, SMLoc NameLoc);859 860  bool parseDirectiveOrg(); // "org"861 862  bool emitAlignTo(int64_t Alignment);863  bool parseDirectiveAlign();  // "align"864  bool parseDirectiveEven();   // "even"865 866  // macro directives867  bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);868  bool parseDirectiveExitMacro(SMLoc DirectiveLoc, StringRef Directive,869                               std::string &Value);870  bool parseDirectiveEndMacro(StringRef Directive);871  bool parseDirectiveMacro(StringRef Name, SMLoc NameLoc);872 873  bool parseDirectiveStruct(StringRef Directive, DirectiveKind DirKind,874                            StringRef Name, SMLoc NameLoc);875  bool parseDirectiveNestedStruct(StringRef Directive, DirectiveKind DirKind);876  bool parseDirectiveEnds(StringRef Name, SMLoc NameLoc);877  bool parseDirectiveNestedEnds();878 879  bool parseDirectiveExtern();880 881  /// Parse a directive like ".globl" which accepts a single symbol (which882  /// should be a label or an external).883  bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);884 885  bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"886 887  bool parseDirectiveComment(SMLoc DirectiveLoc); // "comment"888 889  bool parseDirectiveInclude(); // "include"890 891  // "if" or "ife"892  bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);893  // "ifb" or "ifnb", depending on ExpectBlank.894  bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);895  // "ifidn", "ifdif", "ifidni", or "ifdifi", depending on ExpectEqual and896  // CaseInsensitive.897  bool parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,898                           bool CaseInsensitive);899  // "ifdef" or "ifndef", depending on expect_defined900  bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);901  // "elseif" or "elseife"902  bool parseDirectiveElseIf(SMLoc DirectiveLoc, DirectiveKind DirKind);903  // "elseifb" or "elseifnb", depending on ExpectBlank.904  bool parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank);905  // ".elseifdef" or ".elseifndef", depending on expect_defined906  bool parseDirectiveElseIfdef(SMLoc DirectiveLoc, bool expect_defined);907  // "elseifidn", "elseifdif", "elseifidni", or "elseifdifi", depending on908  // ExpectEqual and CaseInsensitive.909  bool parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,910                               bool CaseInsensitive);911  bool parseDirectiveElse(SMLoc DirectiveLoc);   // "else"912  bool parseDirectiveEndIf(SMLoc DirectiveLoc);  // "endif"913  bool parseEscapedString(std::string &Data) override;914  bool parseAngleBracketString(std::string &Data) override;915 916  // Macro-like directives917  MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);918  void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,919                                raw_svector_ostream &OS);920  void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,921                                SMLoc ExitLoc, raw_svector_ostream &OS);922  bool parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Directive);923  bool parseDirectiveFor(SMLoc DirectiveLoc, StringRef Directive);924  bool parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive);925  bool parseDirectiveWhile(SMLoc DirectiveLoc);926 927  // "_emit" or "__emit"928  bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info,929                            size_t Len);930 931  // "align"932  bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);933 934  // "end"935  bool parseDirectiveEnd(SMLoc DirectiveLoc);936 937  // ".err"938  bool parseDirectiveError(SMLoc DirectiveLoc);939  // ".errb" or ".errnb", depending on ExpectBlank.940  bool parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank);941  // ".errdef" or ".errndef", depending on ExpectBlank.942  bool parseDirectiveErrorIfdef(SMLoc DirectiveLoc, bool ExpectDefined);943  // ".erridn", ".errdif", ".erridni", or ".errdifi", depending on ExpectEqual944  // and CaseInsensitive.945  bool parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,946                                bool CaseInsensitive);947  // ".erre" or ".errnz", depending on ExpectZero.948  bool parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero);949 950  // ".radix"951  bool parseDirectiveRadix(SMLoc DirectiveLoc);952 953  // "echo"954  bool parseDirectiveEcho(SMLoc DirectiveLoc);955 956  void initializeDirectiveKindMap();957  void initializeBuiltinSymbolMaps();958};959 960} // end anonymous namespace961 962namespace llvm {963 964extern cl::opt<unsigned> AsmMacroMaxNestingDepth;965 966} // end namespace llvm967 968enum { DEFAULT_ADDRSPACE = 0 };969 970MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,971                       const MCAsmInfo &MAI, struct tm TM, unsigned CB)972    : MCAsmParser(Ctx, Out, SM, MAI), CurBuffer(CB ? CB : SM.getMainFileID()),973      TM(TM) {974  HadError = false;975  // Save the old handler.976  SavedDiagHandler = SrcMgr.getDiagHandler();977  SavedDiagContext = SrcMgr.getDiagContext();978  // Set our own handler which calls the saved handler.979  SrcMgr.setDiagHandler(DiagHandler, this);980  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());981  EndStatementAtEOFStack.push_back(true);982 983  // Initialize the platform / file format parser.984  switch (Ctx.getObjectFileType()) {985  case MCContext::IsCOFF:986    PlatformParser.reset(createCOFFMasmParser());987    break;988  default:989    report_fatal_error("llvm-ml currently supports only COFF output.");990    break;991  }992 993  initializeDirectiveKindMap();994  PlatformParser->Initialize(*this);995  initializeBuiltinSymbolMaps();996 997  NumOfMacroInstantiations = 0;998}999 1000MasmParser::~MasmParser() {1001  assert((HadError || ActiveMacros.empty()) &&1002         "Unexpected active macro instantiation!");1003 1004  // Restore the saved diagnostics handler and context for use during1005  // finalization.1006  SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext);1007}1008 1009void MasmParser::printMacroInstantiations() {1010  // Print the active macro instantiation stack.1011  for (std::vector<MacroInstantiation *>::const_reverse_iterator1012           it = ActiveMacros.rbegin(),1013           ie = ActiveMacros.rend();1014       it != ie; ++it)1015    printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note,1016                 "while in macro instantiation");1017}1018 1019void MasmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {1020  printPendingErrors();1021  printMessage(L, SourceMgr::DK_Note, Msg, Range);1022  printMacroInstantiations();1023}1024 1025bool MasmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {1026  if (getTargetParser().getTargetOptions().MCNoWarn)1027    return false;1028  if (getTargetParser().getTargetOptions().MCFatalWarnings)1029    return Error(L, Msg, Range);1030  printMessage(L, SourceMgr::DK_Warning, Msg, Range);1031  printMacroInstantiations();1032  return false;1033}1034 1035bool MasmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) {1036  HadError = true;1037  printMessage(L, SourceMgr::DK_Error, Msg, Range);1038  printMacroInstantiations();1039  return true;1040}1041 1042bool MasmParser::enterIncludeFile(const std::string &Filename) {1043  std::string IncludedFile;1044  unsigned NewBuf =1045      SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);1046  if (!NewBuf)1047    return true;1048 1049  CurBuffer = NewBuf;1050  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());1051  EndStatementAtEOFStack.push_back(true);1052  return false;1053}1054 1055void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer,1056                           bool EndStatementAtEOF) {1057  CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc);1058  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),1059                  Loc.getPointer(), EndStatementAtEOF);1060}1061 1062bool MasmParser::expandMacros() {1063  const AsmToken &Tok = getTok();1064  const std::string IDLower = Tok.getIdentifier().lower();1065 1066  const llvm::MCAsmMacro *M = getContext().lookupMacro(IDLower);1067  if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) {1068    // This is a macro function invocation; expand it in place.1069    const SMLoc MacroLoc = Tok.getLoc();1070    const StringRef MacroId = Tok.getIdentifier();1071    Lexer.Lex();1072    if (handleMacroInvocation(M, MacroLoc)) {1073      Lexer.UnLex(AsmToken(AsmToken::Error, MacroId));1074      Lexer.Lex();1075    }1076    return false;1077  }1078 1079  std::optional<std::string> ExpandedValue;1080 1081  if (auto BuiltinIt = BuiltinSymbolMap.find(IDLower);1082      BuiltinIt != BuiltinSymbolMap.end()) {1083    ExpandedValue =1084        evaluateBuiltinTextMacro(BuiltinIt->getValue(), Tok.getLoc());1085  } else if (auto BuiltinFuncIt = BuiltinFunctionMap.find(IDLower);1086             BuiltinFuncIt != BuiltinFunctionMap.end()) {1087    StringRef Name;1088    if (parseIdentifier(Name)) {1089      return true;1090    }1091    std::string Res;1092    if (evaluateBuiltinMacroFunction(BuiltinFuncIt->getValue(), Name, Res)) {1093      return true;1094    }1095    ExpandedValue = Res;1096  } else if (auto VarIt = Variables.find(IDLower);1097             VarIt != Variables.end() && VarIt->getValue().IsText) {1098    ExpandedValue = VarIt->getValue().TextValue;1099  }1100 1101  if (!ExpandedValue)1102    return true;1103  std::unique_ptr<MemoryBuffer> Instantiation =1104      MemoryBuffer::getMemBufferCopy(*ExpandedValue, "<instantiation>");1105 1106  // Jump to the macro instantiation and prime the lexer.1107  CurBuffer =1108      SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());1109  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,1110                  /*EndStatementAtEOF=*/false);1111  EndStatementAtEOFStack.push_back(false);1112  Lexer.Lex();1113  return false;1114}1115 1116const AsmToken &MasmParser::Lex(ExpandKind ExpandNextToken) {1117  if (Lexer.getTok().is(AsmToken::Error))1118    Error(Lexer.getErrLoc(), Lexer.getErr());1119  bool StartOfStatement = false;1120 1121  // if it's a end of statement with a comment in it1122  if (getTok().is(AsmToken::EndOfStatement)) {1123    // if this is a line comment output it.1124    if (!getTok().getString().empty() && getTok().getString().front() != '\n' &&1125        getTok().getString().front() != '\r' && MAI.preserveAsmComments())1126      Out.addExplicitComment(Twine(getTok().getString()));1127    StartOfStatement = true;1128  }1129 1130  const AsmToken *tok = &Lexer.Lex();1131 1132  while (ExpandNextToken == ExpandMacros && tok->is(AsmToken::Identifier)) {1133    if (StartOfStatement) {1134      AsmToken NextTok;1135      MutableArrayRef<AsmToken> Buf(NextTok);1136      size_t ReadCount = Lexer.peekTokens(Buf);1137      if (ReadCount && NextTok.is(AsmToken::Identifier) &&1138          (NextTok.getString().equals_insensitive("equ") ||1139           NextTok.getString().equals_insensitive("textequ"))) {1140        // This looks like an EQU or TEXTEQU directive; don't expand the1141        // identifier, allowing for redefinitions.1142        break;1143      }1144    }1145    if (expandMacros())1146      break;1147  }1148 1149  // Parse comments here to be deferred until end of next statement.1150  while (tok->is(AsmToken::Comment)) {1151    if (MAI.preserveAsmComments())1152      Out.addExplicitComment(Twine(tok->getString()));1153    tok = &Lexer.Lex();1154  }1155 1156  // Recognize and bypass line continuations.1157  while (tok->is(AsmToken::BackSlash) &&1158         peekTok().is(AsmToken::EndOfStatement)) {1159    // Eat both the backslash and the end of statement.1160    Lexer.Lex();1161    tok = &Lexer.Lex();1162  }1163 1164  if (tok->is(AsmToken::Eof)) {1165    // If this is the end of an included file, pop the parent file off the1166    // include stack.1167    SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1168    if (ParentIncludeLoc != SMLoc()) {1169      EndStatementAtEOFStack.pop_back();1170      jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1171      return Lex();1172    }1173    EndStatementAtEOFStack.pop_back();1174    assert(EndStatementAtEOFStack.empty());1175  }1176 1177  return *tok;1178}1179 1180const AsmToken MasmParser::peekTok(bool ShouldSkipSpace) {1181  AsmToken Tok;1182 1183  MutableArrayRef<AsmToken> Buf(Tok);1184  size_t ReadCount = Lexer.peekTokens(Buf, ShouldSkipSpace);1185 1186  if (ReadCount == 0) {1187    // If this is the end of an included file, pop the parent file off the1188    // include stack.1189    SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1190    if (ParentIncludeLoc != SMLoc()) {1191      EndStatementAtEOFStack.pop_back();1192      jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1193      return peekTok(ShouldSkipSpace);1194    }1195    EndStatementAtEOFStack.pop_back();1196    assert(EndStatementAtEOFStack.empty());1197  }1198 1199  assert(ReadCount == 1);1200  return Tok;1201}1202 1203bool MasmParser::Run(bool NoInitialTextSection, bool NoFinalize) {1204  // Create the initial section, if requested.1205  if (!NoInitialTextSection)1206    Out.initSections(false, getTargetParser().getSTI());1207 1208  // Prime the lexer.1209  Lex();1210 1211  HadError = false;1212  AsmCond StartingCondState = TheCondState;1213  SmallVector<AsmRewrite, 4> AsmStrRewrites;1214 1215  // While we have input, parse each statement.1216  while (Lexer.isNot(AsmToken::Eof) ||1217         SrcMgr.getParentIncludeLoc(CurBuffer) != SMLoc()) {1218    // Skip through the EOF at the end of an inclusion.1219    if (Lexer.is(AsmToken::Eof))1220      Lex();1221 1222    ParseStatementInfo Info(&AsmStrRewrites);1223    bool HasError = parseStatement(Info, nullptr);1224 1225    // If we have a Lexer Error we are on an Error Token. Load in Lexer Error1226    // for printing ErrMsg via Lex() only if no (presumably better) parser error1227    // exists.1228    if (HasError && !hasPendingError() && Lexer.getTok().is(AsmToken::Error))1229      Lex();1230 1231    // parseStatement returned true so may need to emit an error.1232    printPendingErrors();1233 1234    // Skipping to the next line if needed.1235    if (HasError && !getLexer().justConsumedEOL())1236      eatToEndOfStatement();1237  }1238 1239  printPendingErrors();1240 1241  // All errors should have been emitted.1242  assert(!hasPendingError() && "unexpected error from parseStatement");1243 1244  if (TheCondState.TheCond != StartingCondState.TheCond ||1245      TheCondState.Ignore != StartingCondState.Ignore)1246    printError(getTok().getLoc(), "unmatched .ifs or .elses");1247 1248  // Check to see that all assembler local symbols were actually defined.1249  // Targets that don't do subsections via symbols may not want this, though,1250  // so conservatively exclude them. Only do this if we're finalizing, though,1251  // as otherwise we won't necessarily have seen everything yet.1252  if (!NoFinalize) {1253    // Temporary symbols like the ones for directional jumps don't go in the1254    // symbol table. They also need to be diagnosed in all (final) cases.1255    for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym : DirLabels) {1256      if (std::get<2>(LocSym)->isUndefined()) {1257        // Reset the state of any "# line file" directives we've seen to the1258        // context as it was at the diagnostic site.1259        CppHashInfo = std::get<1>(LocSym);1260        printError(std::get<0>(LocSym), "directional label undefined");1261      }1262    }1263  }1264 1265  // Finalize the output stream if there are no errors and if the client wants1266  // us to.1267  if (!HadError && !NoFinalize)1268    Out.finish(Lexer.getLoc());1269 1270  return HadError || getContext().hadError();1271}1272 1273bool MasmParser::checkForValidSection() {1274  if (!ParsingMSInlineAsm && !(getStreamer().getCurrentFragment() &&1275                               getStreamer().getCurrentSectionOnly())) {1276    Out.initSections(false, getTargetParser().getSTI());1277    return Error(getTok().getLoc(),1278                 "expected section directive before assembly directive");1279  }1280  return false;1281}1282 1283/// Throw away the rest of the line for testing purposes.1284void MasmParser::eatToEndOfStatement() {1285  while (Lexer.isNot(AsmToken::EndOfStatement)) {1286    if (Lexer.is(AsmToken::Eof)) {1287      SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1288      if (ParentIncludeLoc == SMLoc()) {1289        break;1290      }1291 1292      EndStatementAtEOFStack.pop_back();1293      jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1294    }1295 1296    Lexer.Lex();1297  }1298 1299  // Eat EOL.1300  if (Lexer.is(AsmToken::EndOfStatement))1301    Lexer.Lex();1302}1303 1304SmallVector<StringRef, 1>1305MasmParser::parseStringRefsTo(AsmToken::TokenKind EndTok) {1306  SmallVector<StringRef, 1> Refs;1307  const char *Start = getTok().getLoc().getPointer();1308  while (Lexer.isNot(EndTok)) {1309    if (Lexer.is(AsmToken::Eof)) {1310      SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);1311      if (ParentIncludeLoc == SMLoc()) {1312        break;1313      }1314      Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start);1315 1316      EndStatementAtEOFStack.pop_back();1317      jumpToLoc(ParentIncludeLoc, 0, EndStatementAtEOFStack.back());1318      Lexer.Lex();1319      Start = getTok().getLoc().getPointer();1320    } else {1321      Lexer.Lex();1322    }1323  }1324  Refs.emplace_back(Start, getTok().getLoc().getPointer() - Start);1325  return Refs;1326}1327 1328std::string MasmParser::parseStringTo(AsmToken::TokenKind EndTok) {1329  SmallVector<StringRef, 1> Refs = parseStringRefsTo(EndTok);1330  std::string Str;1331  for (StringRef S : Refs) {1332    Str.append(S.str());1333  }1334  return Str;1335}1336 1337StringRef MasmParser::parseStringToEndOfStatement() {1338  const char *Start = getTok().getLoc().getPointer();1339 1340  while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))1341    Lexer.Lex();1342 1343  const char *End = getTok().getLoc().getPointer();1344  return StringRef(Start, End - Start);1345}1346 1347/// Parse a paren expression and return it.1348/// NOTE: This assumes the leading '(' has already been consumed.1349///1350/// parenexpr ::= expr)1351///1352bool MasmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {1353  if (parseExpression(Res))1354    return true;1355  EndLoc = Lexer.getTok().getEndLoc();1356  return parseRParen();1357}1358 1359/// Parse a bracket expression and return it.1360/// NOTE: This assumes the leading '[' has already been consumed.1361///1362/// bracketexpr ::= expr]1363///1364bool MasmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) {1365  if (parseExpression(Res))1366    return true;1367  EndLoc = getTok().getEndLoc();1368  if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression"))1369    return true;1370  return false;1371}1372 1373/// Parse a primary expression and return it.1374///  primaryexpr ::= (parenexpr1375///  primaryexpr ::= symbol1376///  primaryexpr ::= number1377///  primaryexpr ::= '.'1378///  primaryexpr ::= ~,+,-,'not' primaryexpr1379///  primaryexpr ::= string1380///          (a string is interpreted as a 64-bit number in big-endian base-256)1381bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc,1382                                  AsmTypeInfo *TypeInfo) {1383  SMLoc FirstTokenLoc = getLexer().getLoc();1384  AsmToken::TokenKind FirstTokenKind = Lexer.getKind();1385  switch (FirstTokenKind) {1386  default:1387    return TokError("unknown token in expression");1388  // If we have an error assume that we've already handled it.1389  case AsmToken::Error:1390    return true;1391  case AsmToken::Exclaim:1392    Lex(); // Eat the operator.1393    if (parsePrimaryExpr(Res, EndLoc, nullptr))1394      return true;1395    Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);1396    return false;1397  case AsmToken::Dollar:1398  case AsmToken::At:1399  case AsmToken::Identifier: {1400    StringRef Identifier;1401    if (parseIdentifier(Identifier)) {1402      // We may have failed but $ may be a valid token.1403      if (getTok().is(AsmToken::Dollar)) {1404        if (Lexer.getMAI().getDollarIsPC()) {1405          Lex();1406          // This is a '$' reference, which references the current PC.  Emit a1407          // temporary label to the streamer and refer to it.1408          MCSymbol *Sym = Ctx.createTempSymbol();1409          Out.emitLabel(Sym);1410          Res = MCSymbolRefExpr::create(Sym, getContext());1411          EndLoc = FirstTokenLoc;1412          return false;1413        }1414        return Error(FirstTokenLoc, "invalid token in expression");1415      }1416    }1417    // Parse named bitwise negation.1418    if (Identifier.equals_insensitive("not")) {1419      if (parsePrimaryExpr(Res, EndLoc, nullptr))1420        return true;1421      Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1422      return false;1423    }1424    // Parse directional local label references.1425    if (Identifier.equals_insensitive("@b") ||1426        Identifier.equals_insensitive("@f")) {1427      bool Before = Identifier.equals_insensitive("@b");1428      MCSymbol *Sym = getContext().getDirectionalLocalSymbol(0, Before);1429      if (Before && Sym->isUndefined())1430        return Error(FirstTokenLoc, "Expected @@ label before @B reference");1431      Res = MCSymbolRefExpr::create(Sym, getContext());1432      return false;1433    }1434 1435    EndLoc = SMLoc::getFromPointer(Identifier.end());1436 1437    // This is a symbol reference.1438    StringRef SymbolName = Identifier;1439    if (SymbolName.empty())1440      return Error(getLexer().getLoc(), "expected a symbol reference");1441 1442    // Find the field offset if used.1443    AsmFieldInfo Info;1444    auto Split = SymbolName.split('.');1445    if (Split.second.empty()) {1446    } else {1447      SymbolName = Split.first;1448      if (lookUpField(SymbolName, Split.second, Info)) {1449        std::pair<StringRef, StringRef> BaseMember = Split.second.split('.');1450        StringRef Base = BaseMember.first, Member = BaseMember.second;1451        lookUpField(Base, Member, Info);1452      } else if (Structs.count(SymbolName.lower())) {1453        // This is actually a reference to a field offset.1454        Res = MCConstantExpr::create(Info.Offset, getContext());1455        return false;1456      }1457    }1458 1459    MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName);1460    if (!Sym) {1461      // If this is a built-in numeric value, treat it as a constant.1462      auto BuiltinIt = BuiltinSymbolMap.find(SymbolName.lower());1463      const BuiltinSymbol Symbol = (BuiltinIt == BuiltinSymbolMap.end())1464                                       ? BI_NO_SYMBOL1465                                       : BuiltinIt->getValue();1466      if (Symbol != BI_NO_SYMBOL) {1467        const MCExpr *Value = evaluateBuiltinValue(Symbol, FirstTokenLoc);1468        if (Value) {1469          Res = Value;1470          return false;1471        }1472      }1473 1474      // Variables use case-insensitive symbol names; if this is a variable, we1475      // find the symbol using its canonical name.1476      auto VarIt = Variables.find(SymbolName.lower());1477      if (VarIt != Variables.end())1478        SymbolName = VarIt->second.Name;1479      Sym = getContext().parseSymbol(SymbolName);1480    }1481 1482    // If this is an absolute variable reference, substitute it now to preserve1483    // semantics in the face of reassignment.1484    if (Sym->isVariable()) {1485      auto V = Sym->getVariableValue();1486      bool DoInline = isa<MCConstantExpr>(V);1487      if (auto TV = dyn_cast<MCTargetExpr>(V))1488        DoInline = TV->inlineAssignedExpr();1489      if (DoInline) {1490        Res = Sym->getVariableValue();1491        return false;1492      }1493    }1494 1495    // Otherwise create a symbol ref.1496    const MCExpr *SymRef =1497        MCSymbolRefExpr::create(Sym, getContext(), FirstTokenLoc);1498    if (Info.Offset) {1499      Res = MCBinaryExpr::create(1500          MCBinaryExpr::Add, SymRef,1501          MCConstantExpr::create(Info.Offset, getContext()), getContext());1502    } else {1503      Res = SymRef;1504    }1505    if (TypeInfo) {1506      if (Info.Type.Name.empty()) {1507        auto TypeIt = KnownType.find(Identifier.lower());1508        if (TypeIt != KnownType.end()) {1509          Info.Type = TypeIt->second;1510        }1511      }1512 1513      *TypeInfo = Info.Type;1514    }1515    return false;1516  }1517  case AsmToken::BigNum:1518    return TokError("literal value out of range for directive");1519  case AsmToken::Integer: {1520    int64_t IntVal = getTok().getIntVal();1521    Res = MCConstantExpr::create(IntVal, getContext());1522    EndLoc = Lexer.getTok().getEndLoc();1523    Lex(); // Eat token.1524    return false;1525  }1526  case AsmToken::String: {1527    // MASM strings (used as constants) are interpreted as big-endian base-256.1528    SMLoc ValueLoc = getTok().getLoc();1529    std::string Value;1530    if (parseEscapedString(Value))1531      return true;1532    if (Value.size() > 8)1533      return Error(ValueLoc, "literal value out of range");1534    uint64_t IntValue = 0;1535    for (const unsigned char CharVal : Value)1536      IntValue = (IntValue << 8) | CharVal;1537    Res = MCConstantExpr::create(IntValue, getContext());1538    return false;1539  }1540  case AsmToken::Real: {1541    APFloat RealVal(APFloat::IEEEdouble(), getTok().getString());1542    uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();1543    Res = MCConstantExpr::create(IntVal, getContext());1544    EndLoc = Lexer.getTok().getEndLoc();1545    Lex(); // Eat token.1546    return false;1547  }1548  case AsmToken::Dot: {1549    // This is a '.' reference, which references the current PC.  Emit a1550    // temporary label to the streamer and refer to it.1551    MCSymbol *Sym = Ctx.createTempSymbol();1552    Out.emitLabel(Sym);1553    Res = MCSymbolRefExpr::create(Sym, getContext());1554    EndLoc = Lexer.getTok().getEndLoc();1555    Lex(); // Eat identifier.1556    return false;1557  }1558  case AsmToken::LParen:1559    Lex(); // Eat the '('.1560    return parseParenExpr(Res, EndLoc);1561  case AsmToken::LBrac:1562    if (!PlatformParser->HasBracketExpressions())1563      return TokError("brackets expression not supported on this target");1564    Lex(); // Eat the '['.1565    return parseBracketExpr(Res, EndLoc);1566  case AsmToken::Minus:1567    Lex(); // Eat the operator.1568    if (parsePrimaryExpr(Res, EndLoc, nullptr))1569      return true;1570    Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc);1571    return false;1572  case AsmToken::Plus:1573    Lex(); // Eat the operator.1574    if (parsePrimaryExpr(Res, EndLoc, nullptr))1575      return true;1576    Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc);1577    return false;1578  case AsmToken::Tilde:1579    Lex(); // Eat the operator.1580    if (parsePrimaryExpr(Res, EndLoc, nullptr))1581      return true;1582    Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);1583    return false;1584  }1585}1586 1587bool MasmParser::parseExpression(const MCExpr *&Res) {1588  SMLoc EndLoc;1589  return parseExpression(Res, EndLoc);1590}1591 1592/// This function checks if the next token is <string> type or arithmetic.1593/// string that begin with character '<' must end with character '>'.1594/// otherwise it is arithmetics.1595/// If the function returns a 'true' value,1596/// the End argument will be filled with the last location pointed to the '>'1597/// character.1598static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {1599  assert((StrLoc.getPointer() != nullptr) &&1600         "Argument to the function cannot be a NULL value");1601  const char *CharPtr = StrLoc.getPointer();1602  while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') &&1603         (*CharPtr != '\0')) {1604    if (*CharPtr == '!')1605      CharPtr++;1606    CharPtr++;1607  }1608  if (*CharPtr == '>') {1609    EndLoc = StrLoc.getFromPointer(CharPtr + 1);1610    return true;1611  }1612  return false;1613}1614 1615/// creating a string without the escape characters '!'.1616static std::string angleBracketString(StringRef BracketContents) {1617  std::string Res;1618  for (size_t Pos = 0; Pos < BracketContents.size(); Pos++) {1619    if (BracketContents[Pos] == '!')1620      Pos++;1621    Res += BracketContents[Pos];1622  }1623  return Res;1624}1625 1626/// Parse an expression and return it.1627///1628///  expr ::= expr &&,|| expr               -> lowest.1629///  expr ::= expr |,^,&,! expr1630///  expr ::= expr ==,!=,<>,<,<=,>,>= expr1631///  expr ::= expr <<,>> expr1632///  expr ::= expr +,- expr1633///  expr ::= expr *,/,% expr               -> highest.1634///  expr ::= primaryexpr1635///1636bool MasmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {1637  // Parse the expression.1638  Res = nullptr;1639  if (getTargetParser().parsePrimaryExpr(Res, EndLoc) ||1640      parseBinOpRHS(1, Res, EndLoc))1641    return true;1642 1643  // Try to constant fold it up front, if possible. Do not exploit1644  // assembler here.1645  int64_t Value;1646  if (Res->evaluateAsAbsolute(Value))1647    Res = MCConstantExpr::create(Value, getContext());1648 1649  return false;1650}1651 1652bool MasmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) {1653  Res = nullptr;1654  return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc);1655}1656 1657bool MasmParser::parseAbsoluteExpression(int64_t &Res) {1658  const MCExpr *Expr;1659 1660  SMLoc StartLoc = Lexer.getLoc();1661  if (parseExpression(Expr))1662    return true;1663 1664  if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))1665    return Error(StartLoc, "expected absolute expression");1666 1667  return false;1668}1669 1670static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K,1671                                      MCBinaryExpr::Opcode &Kind,1672                                      bool ShouldUseLogicalShr,1673                                      bool EndExpressionAtGreater) {1674  switch (K) {1675  default:1676    return 0; // not a binop.1677 1678  // Lowest Precedence: &&, ||1679  case AsmToken::AmpAmp:1680    Kind = MCBinaryExpr::LAnd;1681    return 2;1682  case AsmToken::PipePipe:1683    Kind = MCBinaryExpr::LOr;1684    return 1;1685 1686  // Low Precedence: ==, !=, <>, <, <=, >, >=1687  case AsmToken::EqualEqual:1688    Kind = MCBinaryExpr::EQ;1689    return 3;1690  case AsmToken::ExclaimEqual:1691  case AsmToken::LessGreater:1692    Kind = MCBinaryExpr::NE;1693    return 3;1694  case AsmToken::Less:1695    Kind = MCBinaryExpr::LT;1696    return 3;1697  case AsmToken::LessEqual:1698    Kind = MCBinaryExpr::LTE;1699    return 3;1700  case AsmToken::Greater:1701    if (EndExpressionAtGreater)1702      return 0;1703    Kind = MCBinaryExpr::GT;1704    return 3;1705  case AsmToken::GreaterEqual:1706    Kind = MCBinaryExpr::GTE;1707    return 3;1708 1709  // Low Intermediate Precedence: +, -1710  case AsmToken::Plus:1711    Kind = MCBinaryExpr::Add;1712    return 4;1713  case AsmToken::Minus:1714    Kind = MCBinaryExpr::Sub;1715    return 4;1716 1717  // High Intermediate Precedence: |, &, ^1718  case AsmToken::Pipe:1719    Kind = MCBinaryExpr::Or;1720    return 5;1721  case AsmToken::Caret:1722    Kind = MCBinaryExpr::Xor;1723    return 5;1724  case AsmToken::Amp:1725    Kind = MCBinaryExpr::And;1726    return 5;1727 1728  // Highest Precedence: *, /, %, <<, >>1729  case AsmToken::Star:1730    Kind = MCBinaryExpr::Mul;1731    return 6;1732  case AsmToken::Slash:1733    Kind = MCBinaryExpr::Div;1734    return 6;1735  case AsmToken::Percent:1736    Kind = MCBinaryExpr::Mod;1737    return 6;1738  case AsmToken::LessLess:1739    Kind = MCBinaryExpr::Shl;1740    return 6;1741  case AsmToken::GreaterGreater:1742    if (EndExpressionAtGreater)1743      return 0;1744    Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;1745    return 6;1746  }1747}1748 1749unsigned MasmParser::getBinOpPrecedence(AsmToken::TokenKind K,1750                                        MCBinaryExpr::Opcode &Kind) {1751  bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();1752  return getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr,1753                               AngleBracketDepth > 0);1754}1755 1756/// Parse all binary operators with precedence >= 'Precedence'.1757/// Res contains the LHS of the expression on input.1758bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,1759                               SMLoc &EndLoc) {1760  SMLoc StartLoc = Lexer.getLoc();1761  while (true) {1762    AsmToken::TokenKind TokKind = Lexer.getKind();1763    if (Lexer.getKind() == AsmToken::Identifier) {1764      TokKind = StringSwitch<AsmToken::TokenKind>(Lexer.getTok().getString())1765                    .CaseLower("and", AsmToken::Amp)1766                    .CaseLower("not", AsmToken::Exclaim)1767                    .CaseLower("or", AsmToken::Pipe)1768                    .CaseLower("xor", AsmToken::Caret)1769                    .CaseLower("shl", AsmToken::LessLess)1770                    .CaseLower("shr", AsmToken::GreaterGreater)1771                    .CaseLower("eq", AsmToken::EqualEqual)1772                    .CaseLower("ne", AsmToken::ExclaimEqual)1773                    .CaseLower("lt", AsmToken::Less)1774                    .CaseLower("le", AsmToken::LessEqual)1775                    .CaseLower("gt", AsmToken::Greater)1776                    .CaseLower("ge", AsmToken::GreaterEqual)1777                    .Default(TokKind);1778    }1779    MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;1780    unsigned TokPrec = getBinOpPrecedence(TokKind, Kind);1781 1782    // If the next token is lower precedence than we are allowed to eat, return1783    // successfully with what we ate already.1784    if (TokPrec < Precedence)1785      return false;1786 1787    Lex();1788 1789    // Eat the next primary expression.1790    const MCExpr *RHS;1791    if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))1792      return true;1793 1794    // If BinOp binds less tightly with RHS than the operator after RHS, let1795    // the pending operator take RHS as its LHS.1796    MCBinaryExpr::Opcode Dummy;1797    unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy);1798    if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc))1799      return true;1800 1801    // Merge LHS and RHS according to operator.1802    Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(), StartLoc);1803  }1804}1805 1806/// ParseStatement:1807///   ::= % statement1808///   ::= EndOfStatement1809///   ::= Label* Directive ...Operands... EndOfStatement1810///   ::= Label* Identifier OperandList* EndOfStatement1811bool MasmParser::parseStatement(ParseStatementInfo &Info,1812                                MCAsmParserSemaCallback *SI) {1813  assert(!hasPendingError() && "parseStatement started with pending error");1814  // Eat initial spaces and comments.1815  while (Lexer.is(AsmToken::Space))1816    Lex();1817  if (Lexer.is(AsmToken::EndOfStatement)) {1818    // If this is a line comment we can drop it safely.1819    if (getTok().getString().empty() || getTok().getString().front() == '\r' ||1820        getTok().getString().front() == '\n')1821      Out.addBlankLine();1822    Lex();1823    return false;1824  }1825 1826  // If preceded by an expansion operator, first expand all text macros and1827  // macro functions.1828  if (getTok().is(AsmToken::Percent)) {1829    SMLoc ExpansionLoc = getTok().getLoc();1830    if (parseToken(AsmToken::Percent) || expandStatement(ExpansionLoc))1831      return true;1832  }1833 1834  // Statements always start with an identifier, unless we're dealing with a1835  // processor directive (.386, .686, etc.) that lexes as a real.1836  AsmToken ID = getTok();1837  SMLoc IDLoc = ID.getLoc();1838  StringRef IDVal;1839  if (Lexer.is(AsmToken::HashDirective))1840    return parseCppHashLineFilenameComment(IDLoc);1841  if (Lexer.is(AsmToken::Dot)) {1842    // Treat '.' as a valid identifier in this context.1843    Lex();1844    IDVal = ".";1845  } else if (Lexer.is(AsmToken::Real)) {1846    // Treat ".<number>" as a valid identifier in this context.1847    IDVal = getTok().getString();1848    Lex(); // always eat a token1849    if (!IDVal.starts_with("."))1850      return Error(IDLoc, "unexpected token at start of statement");1851  } else if (parseIdentifier(IDVal, StartOfStatement)) {1852    if (!TheCondState.Ignore) {1853      Lex(); // always eat a token1854      return Error(IDLoc, "unexpected token at start of statement");1855    }1856    IDVal = "";1857  }1858 1859  // Handle conditional assembly here before checking for skipping.  We1860  // have to do this so that .endif isn't skipped in a ".if 0" block for1861  // example.1862  StringMap<DirectiveKind>::const_iterator DirKindIt =1863      DirectiveKindMap.find(IDVal.lower());1864  DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())1865                              ? DK_NO_DIRECTIVE1866                              : DirKindIt->getValue();1867  switch (DirKind) {1868  default:1869    break;1870  case DK_IF:1871  case DK_IFE:1872    return parseDirectiveIf(IDLoc, DirKind);1873  case DK_IFB:1874    return parseDirectiveIfb(IDLoc, true);1875  case DK_IFNB:1876    return parseDirectiveIfb(IDLoc, false);1877  case DK_IFDEF:1878    return parseDirectiveIfdef(IDLoc, true);1879  case DK_IFNDEF:1880    return parseDirectiveIfdef(IDLoc, false);1881  case DK_IFDIF:1882    return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,1883                               /*CaseInsensitive=*/false);1884  case DK_IFDIFI:1885    return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/false,1886                               /*CaseInsensitive=*/true);1887  case DK_IFIDN:1888    return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,1889                               /*CaseInsensitive=*/false);1890  case DK_IFIDNI:1891    return parseDirectiveIfidn(IDLoc, /*ExpectEqual=*/true,1892                               /*CaseInsensitive=*/true);1893  case DK_ELSEIF:1894  case DK_ELSEIFE:1895    return parseDirectiveElseIf(IDLoc, DirKind);1896  case DK_ELSEIFB:1897    return parseDirectiveElseIfb(IDLoc, true);1898  case DK_ELSEIFNB:1899    return parseDirectiveElseIfb(IDLoc, false);1900  case DK_ELSEIFDEF:1901    return parseDirectiveElseIfdef(IDLoc, true);1902  case DK_ELSEIFNDEF:1903    return parseDirectiveElseIfdef(IDLoc, false);1904  case DK_ELSEIFDIF:1905    return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,1906                                   /*CaseInsensitive=*/false);1907  case DK_ELSEIFDIFI:1908    return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/false,1909                                   /*CaseInsensitive=*/true);1910  case DK_ELSEIFIDN:1911    return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,1912                                   /*CaseInsensitive=*/false);1913  case DK_ELSEIFIDNI:1914    return parseDirectiveElseIfidn(IDLoc, /*ExpectEqual=*/true,1915                                   /*CaseInsensitive=*/true);1916  case DK_ELSE:1917    return parseDirectiveElse(IDLoc);1918  case DK_ENDIF:1919    return parseDirectiveEndIf(IDLoc);1920  }1921 1922  // Ignore the statement if in the middle of inactive conditional1923  // (e.g. ".if 0").1924  if (TheCondState.Ignore) {1925    eatToEndOfStatement();1926    return false;1927  }1928 1929  // FIXME: Recurse on local labels?1930 1931  // Check for a label.1932  //   ::= identifier ':'1933  //   ::= number ':'1934  if (Lexer.is(AsmToken::Colon) && getTargetParser().isLabel(ID)) {1935    if (checkForValidSection())1936      return true;1937 1938    // identifier ':'   -> Label.1939    Lex();1940 1941    // Diagnose attempt to use '.' as a label.1942    if (IDVal == ".")1943      return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label");1944 1945    // Diagnose attempt to use a variable as a label.1946    //1947    // FIXME: Diagnostics. Note the location of the definition as a label.1948    // FIXME: This doesn't diagnose assignment to a symbol which has been1949    // implicitly marked as external.1950    MCSymbol *Sym;1951    if (ParsingMSInlineAsm && SI) {1952      StringRef RewrittenLabel =1953          SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);1954      assert(!RewrittenLabel.empty() &&1955             "We should have an internal name here.");1956      Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),1957                                     RewrittenLabel);1958      IDVal = RewrittenLabel;1959    }1960    // Handle directional local labels1961    if (IDVal == "@@") {1962      Sym = Ctx.createDirectionalLocalSymbol(0);1963    } else {1964      Sym = getContext().parseSymbol(IDVal);1965    }1966 1967    // End of Labels should be treated as end of line for lexing1968    // purposes but that information is not available to the Lexer who1969    // does not understand Labels. This may cause us to see a Hash1970    // here instead of a preprocessor line comment.1971    if (getTok().is(AsmToken::Hash)) {1972      std::string CommentStr = parseStringTo(AsmToken::EndOfStatement);1973      Lexer.Lex();1974      Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));1975    }1976 1977    // Consume any end of statement token, if present, to avoid spurious1978    // addBlankLine calls().1979    if (getTok().is(AsmToken::EndOfStatement)) {1980      Lex();1981    }1982 1983    // Emit the label.1984    if (!getTargetParser().isParsingMSInlineAsm())1985      Out.emitLabel(Sym, IDLoc);1986    return false;1987  }1988 1989  // If macros are enabled, check to see if this is a macro instantiation.1990  if (const MCAsmMacro *M = getContext().lookupMacro(IDVal.lower())) {1991    AsmToken::TokenKind ArgumentEndTok = parseOptionalToken(AsmToken::LParen)1992                                             ? AsmToken::RParen1993                                             : AsmToken::EndOfStatement;1994    return handleMacroEntry(M, IDLoc, ArgumentEndTok);1995  }1996 1997  // Otherwise, we have a normal instruction or directive.1998 1999  if (DirKind != DK_NO_DIRECTIVE) {2000    // There are several entities interested in parsing directives:2001    //2002    // 1. Asm parser extensions. For example, platform-specific parsers2003    //    (like the ELF parser) register themselves as extensions.2004    // 2. The target-specific assembly parser. Some directives are target2005    //    specific or may potentially behave differently on certain targets.2006    // 3. The generic directive parser implemented by this class. These are2007    //    all the directives that behave in a target and platform independent2008    //    manner, or at least have a default behavior that's shared between2009    //    all targets and platforms.2010 2011    // Special-case handling of structure-end directives at higher priority,2012    // since ENDS is overloaded as a segment-end directive.2013    if (IDVal.equals_insensitive("ends") && StructInProgress.size() > 1 &&2014        getTok().is(AsmToken::EndOfStatement)) {2015      return parseDirectiveNestedEnds();2016    }2017 2018    // First, check the extension directive map to see if any extension has2019    // registered itself to parse this directive.2020    std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =2021        ExtensionDirectiveMap.lookup(IDVal.lower());2022    if (Handler.first)2023      return (*Handler.second)(Handler.first, IDVal, IDLoc);2024 2025    // Next, let the target-specific assembly parser try.2026    if (ID.isNot(AsmToken::Identifier))2027      return false;2028 2029    ParseStatus TPDirectiveReturn = getTargetParser().parseDirective(ID);2030    assert(TPDirectiveReturn.isFailure() == hasPendingError() &&2031           "Should only return Failure iff there was an error");2032    if (TPDirectiveReturn.isFailure())2033      return true;2034    if (TPDirectiveReturn.isSuccess())2035      return false;2036 2037    // Finally, if no one else is interested in this directive, it must be2038    // generic and familiar to this class.2039    switch (DirKind) {2040    default:2041      break;2042    case DK_ASCII:2043      return parseDirectiveAscii(IDVal, false);2044    case DK_ASCIZ:2045    case DK_STRING:2046      return parseDirectiveAscii(IDVal, true);2047    case DK_BYTE:2048    case DK_SBYTE:2049    case DK_DB:2050      return parseDirectiveValue(IDVal, 1);2051    case DK_WORD:2052    case DK_SWORD:2053    case DK_DW:2054      return parseDirectiveValue(IDVal, 2);2055    case DK_DWORD:2056    case DK_SDWORD:2057    case DK_DD:2058      return parseDirectiveValue(IDVal, 4);2059    case DK_FWORD:2060    case DK_DF:2061      return parseDirectiveValue(IDVal, 6);2062    case DK_QWORD:2063    case DK_SQWORD:2064    case DK_DQ:2065      return parseDirectiveValue(IDVal, 8);2066    case DK_REAL4:2067      return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle(), 4);2068    case DK_REAL8:2069      return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble(), 8);2070    case DK_REAL10:2071      return parseDirectiveRealValue(IDVal, APFloat::x87DoubleExtended(), 10);2072    case DK_STRUCT:2073    case DK_UNION:2074      return parseDirectiveNestedStruct(IDVal, DirKind);2075    case DK_ENDS:2076      return parseDirectiveNestedEnds();2077    case DK_ALIGN:2078      return parseDirectiveAlign();2079    case DK_EVEN:2080      return parseDirectiveEven();2081    case DK_ORG:2082      return parseDirectiveOrg();2083    case DK_EXTERN:2084      return parseDirectiveExtern();2085    case DK_PUBLIC:2086      return parseDirectiveSymbolAttribute(MCSA_Global);2087    case DK_COMM:2088      return parseDirectiveComm(/*IsLocal=*/false);2089    case DK_COMMENT:2090      return parseDirectiveComment(IDLoc);2091    case DK_INCLUDE:2092      return parseDirectiveInclude();2093    case DK_REPEAT:2094      return parseDirectiveRepeat(IDLoc, IDVal);2095    case DK_WHILE:2096      return parseDirectiveWhile(IDLoc);2097    case DK_FOR:2098      return parseDirectiveFor(IDLoc, IDVal);2099    case DK_FORC:2100      return parseDirectiveForc(IDLoc, IDVal);2101    case DK_EXITM:2102      Info.ExitValue = "";2103      return parseDirectiveExitMacro(IDLoc, IDVal, *Info.ExitValue);2104    case DK_ENDM:2105      Info.ExitValue = "";2106      return parseDirectiveEndMacro(IDVal);2107    case DK_PURGE:2108      return parseDirectivePurgeMacro(IDLoc);2109    case DK_END:2110      return parseDirectiveEnd(IDLoc);2111    case DK_ERR:2112      return parseDirectiveError(IDLoc);2113    case DK_ERRB:2114      return parseDirectiveErrorIfb(IDLoc, true);2115    case DK_ERRNB:2116      return parseDirectiveErrorIfb(IDLoc, false);2117    case DK_ERRDEF:2118      return parseDirectiveErrorIfdef(IDLoc, true);2119    case DK_ERRNDEF:2120      return parseDirectiveErrorIfdef(IDLoc, false);2121    case DK_ERRDIF:2122      return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,2123                                      /*CaseInsensitive=*/false);2124    case DK_ERRDIFI:2125      return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/false,2126                                      /*CaseInsensitive=*/true);2127    case DK_ERRIDN:2128      return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,2129                                      /*CaseInsensitive=*/false);2130    case DK_ERRIDNI:2131      return parseDirectiveErrorIfidn(IDLoc, /*ExpectEqual=*/true,2132                                      /*CaseInsensitive=*/true);2133    case DK_ERRE:2134      return parseDirectiveErrorIfe(IDLoc, true);2135    case DK_ERRNZ:2136      return parseDirectiveErrorIfe(IDLoc, false);2137    case DK_RADIX:2138      return parseDirectiveRadix(IDLoc);2139    case DK_ECHO:2140      return parseDirectiveEcho(IDLoc);2141    }2142 2143    return Error(IDLoc, "unknown directive");2144  }2145 2146  // We also check if this is allocating memory with user-defined type.2147  auto IDIt = Structs.find(IDVal.lower());2148  if (IDIt != Structs.end())2149    return parseDirectiveStructValue(/*Structure=*/IDIt->getValue(), IDVal,2150                                     IDLoc);2151 2152  // Non-conditional Microsoft directives sometimes follow their first argument.2153  const AsmToken nextTok = getTok();2154  const StringRef nextVal = nextTok.getString();2155  const SMLoc nextLoc = nextTok.getLoc();2156 2157  const AsmToken afterNextTok = peekTok();2158 2159  // There are several entities interested in parsing infix directives:2160  //2161  // 1. Asm parser extensions. For example, platform-specific parsers2162  //    (like the ELF parser) register themselves as extensions.2163  // 2. The generic directive parser implemented by this class. These are2164  //    all the directives that behave in a target and platform independent2165  //    manner, or at least have a default behavior that's shared between2166  //    all targets and platforms.2167 2168  getTargetParser().flushPendingInstructions(getStreamer());2169 2170  // Special-case handling of structure-end directives at higher priority, since2171  // ENDS is overloaded as a segment-end directive.2172  if (nextVal.equals_insensitive("ends") && StructInProgress.size() == 1) {2173    Lex();2174    return parseDirectiveEnds(IDVal, IDLoc);2175  }2176 2177  // First, check the extension directive map to see if any extension has2178  // registered itself to parse this directive.2179  std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =2180      ExtensionDirectiveMap.lookup(nextVal.lower());2181  if (Handler.first) {2182    Lex();2183    Lexer.UnLex(ID);2184    return (*Handler.second)(Handler.first, nextVal, nextLoc);2185  }2186 2187  // If no one else is interested in this directive, it must be2188  // generic and familiar to this class.2189  DirKindIt = DirectiveKindMap.find(nextVal.lower());2190  DirKind = (DirKindIt == DirectiveKindMap.end())2191                ? DK_NO_DIRECTIVE2192                : DirKindIt->getValue();2193  switch (DirKind) {2194  default:2195    break;2196  case DK_ASSIGN:2197  case DK_EQU:2198  case DK_TEXTEQU:2199    Lex();2200    return parseDirectiveEquate(nextVal, IDVal, DirKind, IDLoc);2201  case DK_BYTE:2202    if (afterNextTok.is(AsmToken::Identifier) &&2203        afterNextTok.getString().equals_insensitive("ptr")) {2204      // Size directive; part of an instruction.2205      break;2206    }2207    [[fallthrough]];2208  case DK_SBYTE:2209  case DK_DB:2210    Lex();2211    return parseDirectiveNamedValue(nextVal, 1, IDVal, IDLoc);2212  case DK_WORD:2213    if (afterNextTok.is(AsmToken::Identifier) &&2214        afterNextTok.getString().equals_insensitive("ptr")) {2215      // Size directive; part of an instruction.2216      break;2217    }2218    [[fallthrough]];2219  case DK_SWORD:2220  case DK_DW:2221    Lex();2222    return parseDirectiveNamedValue(nextVal, 2, IDVal, IDLoc);2223  case DK_DWORD:2224    if (afterNextTok.is(AsmToken::Identifier) &&2225        afterNextTok.getString().equals_insensitive("ptr")) {2226      // Size directive; part of an instruction.2227      break;2228    }2229    [[fallthrough]];2230  case DK_SDWORD:2231  case DK_DD:2232    Lex();2233    return parseDirectiveNamedValue(nextVal, 4, IDVal, IDLoc);2234  case DK_FWORD:2235    if (afterNextTok.is(AsmToken::Identifier) &&2236        afterNextTok.getString().equals_insensitive("ptr")) {2237      // Size directive; part of an instruction.2238      break;2239    }2240    [[fallthrough]];2241  case DK_DF:2242    Lex();2243    return parseDirectiveNamedValue(nextVal, 6, IDVal, IDLoc);2244  case DK_QWORD:2245    if (afterNextTok.is(AsmToken::Identifier) &&2246        afterNextTok.getString().equals_insensitive("ptr")) {2247      // Size directive; part of an instruction.2248      break;2249    }2250    [[fallthrough]];2251  case DK_SQWORD:2252  case DK_DQ:2253    Lex();2254    return parseDirectiveNamedValue(nextVal, 8, IDVal, IDLoc);2255  case DK_REAL4:2256    Lex();2257    return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEsingle(), 4,2258                                        IDVal, IDLoc);2259  case DK_REAL8:2260    Lex();2261    return parseDirectiveNamedRealValue(nextVal, APFloat::IEEEdouble(), 8,2262                                        IDVal, IDLoc);2263  case DK_REAL10:2264    Lex();2265    return parseDirectiveNamedRealValue(nextVal, APFloat::x87DoubleExtended(),2266                                        10, IDVal, IDLoc);2267  case DK_STRUCT:2268  case DK_UNION:2269    Lex();2270    return parseDirectiveStruct(nextVal, DirKind, IDVal, IDLoc);2271  case DK_ENDS:2272    Lex();2273    return parseDirectiveEnds(IDVal, IDLoc);2274  case DK_MACRO:2275    Lex();2276    return parseDirectiveMacro(IDVal, IDLoc);2277  }2278 2279  // Finally, we check if this is allocating a variable with user-defined type.2280  auto NextIt = Structs.find(nextVal.lower());2281  if (NextIt != Structs.end()) {2282    Lex();2283    return parseDirectiveNamedStructValue(/*Structure=*/NextIt->getValue(),2284                                          nextVal, nextLoc, IDVal);2285  }2286 2287  // __asm _emit or __asm __emit2288  if (ParsingMSInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||2289                             IDVal == "_EMIT" || IDVal == "__EMIT"))2290    return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());2291 2292  // __asm align2293  if (ParsingMSInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))2294    return parseDirectiveMSAlign(IDLoc, Info);2295 2296  if (ParsingMSInlineAsm && (IDVal == "even" || IDVal == "EVEN"))2297    Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);2298  if (checkForValidSection())2299    return true;2300 2301  // Canonicalize the opcode to lower case.2302  std::string OpcodeStr = IDVal.lower();2303  ParseInstructionInfo IInfo(Info.AsmRewrites);2304  bool ParseHadError = getTargetParser().parseInstruction(IInfo, OpcodeStr, ID,2305                                                          Info.ParsedOperands);2306  Info.ParseError = ParseHadError;2307 2308  // Dump the parsed representation, if requested.2309  if (getShowParsedOperands()) {2310    SmallString<256> Str;2311    raw_svector_ostream OS(Str);2312    OS << "parsed instruction: [";2313    for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {2314      if (i != 0)2315        OS << ", ";2316      Info.ParsedOperands[i]->print(OS, MAI);2317    }2318    OS << "]";2319 2320    printMessage(IDLoc, SourceMgr::DK_Note, OS.str());2321  }2322 2323  // Fail even if ParseInstruction erroneously returns false.2324  if (hasPendingError() || ParseHadError)2325    return true;2326 2327  // If parsing succeeded, match the instruction.2328  if (!ParseHadError) {2329    uint64_t ErrorInfo;2330    if (getTargetParser().matchAndEmitInstruction(2331            IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,2332            getTargetParser().isParsingMSInlineAsm()))2333      return true;2334  }2335  return false;2336}2337 2338// Parse and erase curly braces marking block start/end.2339bool MasmParser::parseCurlyBlockScope(2340    SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {2341  // Identify curly brace marking block start/end.2342  if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly))2343    return false;2344 2345  SMLoc StartLoc = Lexer.getLoc();2346  Lex(); // Eat the brace.2347  if (Lexer.is(AsmToken::EndOfStatement))2348    Lex(); // Eat EndOfStatement following the brace.2349 2350  // Erase the block start/end brace from the output asm string.2351  AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() -2352                                                  StartLoc.getPointer());2353  return true;2354}2355 2356/// parseCppHashLineFilenameComment as this:2357///   ::= # number "filename"2358bool MasmParser::parseCppHashLineFilenameComment(SMLoc L) {2359  Lex(); // Eat the hash token.2360  // Lexer only ever emits HashDirective if it fully formed if it's2361  // done the checking already so this is an internal error.2362  assert(getTok().is(AsmToken::Integer) &&2363         "Lexing Cpp line comment: Expected Integer");2364  int64_t LineNumber = getTok().getIntVal();2365  Lex();2366  assert(getTok().is(AsmToken::String) &&2367         "Lexing Cpp line comment: Expected String");2368  StringRef Filename = getTok().getString();2369  Lex();2370 2371  // Get rid of the enclosing quotes.2372  Filename = Filename.substr(1, Filename.size() - 2);2373 2374  // Save the SMLoc, Filename and LineNumber for later use by diagnostics2375  // and possibly DWARF file info.2376  CppHashInfo.Loc = L;2377  CppHashInfo.Filename = Filename;2378  CppHashInfo.LineNumber = LineNumber;2379  CppHashInfo.Buf = CurBuffer;2380  if (FirstCppHashFilename.empty())2381    FirstCppHashFilename = Filename;2382  return false;2383}2384 2385/// will use the last parsed cpp hash line filename comment2386/// for the Filename and LineNo if any in the diagnostic.2387void MasmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {2388  const MasmParser *Parser = static_cast<const MasmParser *>(Context);2389  raw_ostream &OS = errs();2390 2391  const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();2392  SMLoc DiagLoc = Diag.getLoc();2393  unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2394  unsigned CppHashBuf =2395      Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc);2396 2397  // Like SourceMgr::printMessage() we need to print the include stack if any2398  // before printing the message.2399  unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);2400  if (!Parser->SavedDiagHandler && DiagCurBuffer &&2401      DiagCurBuffer != DiagSrcMgr.getMainFileID()) {2402    SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);2403    DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);2404  }2405 2406  // If we have not parsed a cpp hash line filename comment or the source2407  // manager changed or buffer changed (like in a nested include) then just2408  // print the normal diagnostic using its Filename and LineNo.2409  if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr ||2410      DiagBuf != CppHashBuf) {2411    if (Parser->SavedDiagHandler)2412      Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);2413    else2414      Diag.print(nullptr, OS);2415    return;2416  }2417 2418  // Use the CppHashFilename and calculate a line number based on the2419  // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc2420  // for the diagnostic.2421  const std::string &Filename = std::string(Parser->CppHashInfo.Filename);2422 2423  int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);2424  int CppHashLocLineNo =2425      Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf);2426  int LineNo =2427      Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);2428 2429  SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,2430                       Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),2431                       Diag.getLineContents(), Diag.getRanges());2432 2433  if (Parser->SavedDiagHandler)2434    Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);2435  else2436    NewDiag.print(nullptr, OS);2437}2438 2439// This is similar to the IsIdentifierChar function in AsmLexer.cpp, but does2440// not accept '.'.2441static bool isMacroParameterChar(char C) {2442  return isAlnum(C) || C == '_' || C == '$' || C == '@' || C == '?';2443}2444 2445bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,2446                             ArrayRef<MCAsmMacroParameter> Parameters,2447                             ArrayRef<MCAsmMacroArgument> A,2448                             const std::vector<std::string> &Locals, SMLoc L) {2449  unsigned NParameters = Parameters.size();2450  if (NParameters != A.size())2451    return Error(L, "Wrong number of arguments");2452  StringMap<std::string> LocalSymbols;2453  std::string Name;2454  Name.reserve(6);2455  for (StringRef Local : Locals) {2456    raw_string_ostream LocalName(Name);2457    LocalName << "??"2458              << format_hex_no_prefix(LocalCounter++, 4, /*Upper=*/true);2459    LocalSymbols.insert({Local, Name});2460    Name.clear();2461  }2462 2463  std::optional<char> CurrentQuote;2464  while (!Body.empty()) {2465    // Scan for the next substitution.2466    std::size_t End = Body.size(), Pos = 0;2467    std::size_t IdentifierPos = End;2468    for (; Pos != End; ++Pos) {2469      // Find the next possible macro parameter, including preceding a '&'2470      // inside quotes.2471      if (Body[Pos] == '&')2472        break;2473      if (isMacroParameterChar(Body[Pos])) {2474        if (!CurrentQuote)2475          break;2476        if (IdentifierPos == End)2477          IdentifierPos = Pos;2478      } else {2479        IdentifierPos = End;2480      }2481 2482      // Track quotation status2483      if (!CurrentQuote) {2484        if (Body[Pos] == '\'' || Body[Pos] == '"')2485          CurrentQuote = Body[Pos];2486      } else if (Body[Pos] == CurrentQuote) {2487        if (Pos + 1 != End && Body[Pos + 1] == CurrentQuote) {2488          // Escaped quote, and quotes aren't identifier chars; skip2489          ++Pos;2490          continue;2491        } else {2492          CurrentQuote.reset();2493        }2494      }2495    }2496    if (IdentifierPos != End) {2497      // We've recognized an identifier before an apostrophe inside quotes;2498      // check once to see if we can expand it.2499      Pos = IdentifierPos;2500      IdentifierPos = End;2501    }2502 2503    // Add the prefix.2504    OS << Body.slice(0, Pos);2505 2506    // Check if we reached the end.2507    if (Pos == End)2508      break;2509 2510    unsigned I = Pos;2511    bool InitialAmpersand = (Body[I] == '&');2512    if (InitialAmpersand) {2513      ++I;2514      ++Pos;2515    }2516    while (I < End && isMacroParameterChar(Body[I]))2517      ++I;2518 2519    const char *Begin = Body.data() + Pos;2520    StringRef Argument(Begin, I - Pos);2521    const std::string ArgumentLower = Argument.lower();2522    unsigned Index = 0;2523 2524    for (; Index < NParameters; ++Index)2525      if (Parameters[Index].Name.equals_insensitive(ArgumentLower))2526        break;2527 2528    if (Index == NParameters) {2529      if (InitialAmpersand)2530        OS << '&';2531      auto it = LocalSymbols.find(ArgumentLower);2532      if (it != LocalSymbols.end())2533        OS << it->second;2534      else2535        OS << Argument;2536      Pos = I;2537    } else {2538      for (const AsmToken &Token : A[Index]) {2539        // In MASM, you can write '%expr'.2540        // The prefix '%' evaluates the expression 'expr'2541        // and uses the result as a string (e.g. replace %(1+2) with the2542        // string "3").2543        // Here, we identify the integer token which is the result of the2544        // absolute expression evaluation and replace it with its string2545        // representation.2546        if (Token.getString().front() == '%' && Token.is(AsmToken::Integer))2547          // Emit an integer value to the buffer.2548          OS << Token.getIntVal();2549        else2550          OS << Token.getString();2551      }2552 2553      Pos += Argument.size();2554      if (Pos < End && Body[Pos] == '&') {2555        ++Pos;2556      }2557    }2558    // Update the scan point.2559    Body = Body.substr(Pos);2560  }2561 2562  return false;2563}2564 2565bool MasmParser::parseMacroArgument(const MCAsmMacroParameter *MP,2566                                    MCAsmMacroArgument &MA,2567                                    AsmToken::TokenKind EndTok) {2568  if (MP && MP->Vararg) {2569    if (Lexer.isNot(EndTok)) {2570      SmallVector<StringRef, 1> Str = parseStringRefsTo(EndTok);2571      for (StringRef S : Str) {2572        MA.emplace_back(AsmToken::String, S);2573      }2574    }2575    return false;2576  }2577 2578  SMLoc StrLoc = Lexer.getLoc(), EndLoc;2579  if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) {2580    const char *StrChar = StrLoc.getPointer() + 1;2581    const char *EndChar = EndLoc.getPointer() - 1;2582    jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back());2583    /// Eat from '<' to '>'.2584    Lex();2585    MA.emplace_back(AsmToken::String, StringRef(StrChar, EndChar - StrChar));2586    return false;2587  }2588 2589  unsigned ParenLevel = 0;2590 2591  while (true) {2592    if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))2593      return TokError("unexpected token");2594 2595    if (ParenLevel == 0 && Lexer.is(AsmToken::Comma))2596      break;2597 2598    // handleMacroEntry relies on not advancing the lexer here2599    // to be able to fill in the remaining default parameter values2600    if (Lexer.is(EndTok) && (EndTok != AsmToken::RParen || ParenLevel == 0))2601      break;2602 2603    // Adjust the current parentheses level.2604    if (Lexer.is(AsmToken::LParen))2605      ++ParenLevel;2606    else if (Lexer.is(AsmToken::RParen) && ParenLevel)2607      --ParenLevel;2608 2609    // Append the token to the current argument list.2610    MA.push_back(getTok());2611    Lex();2612  }2613 2614  if (ParenLevel != 0)2615    return TokError("unbalanced parentheses in argument");2616 2617  if (MA.empty() && MP) {2618    if (MP->Required) {2619      return TokError("missing value for required parameter '" + MP->Name +2620                      "'");2621    } else {2622      MA = MP->Value;2623    }2624  }2625  return false;2626}2627 2628// Parse the macro instantiation arguments.2629bool MasmParser::parseMacroArguments(const MCAsmMacro *M,2630                                     MCAsmMacroArguments &A,2631                                     AsmToken::TokenKind EndTok) {2632  const unsigned NParameters = M ? M->Parameters.size() : 0;2633  bool NamedParametersFound = false;2634  SmallVector<SMLoc, 4> FALocs;2635 2636  A.resize(NParameters);2637  FALocs.resize(NParameters);2638 2639  // Parse two kinds of macro invocations:2640  // - macros defined without any parameters accept an arbitrary number of them2641  // - macros defined with parameters accept at most that many of them2642  for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;2643       ++Parameter) {2644    SMLoc IDLoc = Lexer.getLoc();2645    MCAsmMacroParameter FA;2646 2647    if (Lexer.is(AsmToken::Identifier) && peekTok().is(AsmToken::Equal)) {2648      if (parseIdentifier(FA.Name))2649        return Error(IDLoc, "invalid argument identifier for formal argument");2650 2651      if (Lexer.isNot(AsmToken::Equal))2652        return TokError("expected '=' after formal parameter identifier");2653 2654      Lex();2655 2656      NamedParametersFound = true;2657    }2658 2659    if (NamedParametersFound && FA.Name.empty())2660      return Error(IDLoc, "cannot mix positional and keyword arguments");2661 2662    unsigned PI = Parameter;2663    if (!FA.Name.empty()) {2664      assert(M && "expected macro to be defined");2665      unsigned FAI = 0;2666      for (FAI = 0; FAI < NParameters; ++FAI)2667        if (M->Parameters[FAI].Name == FA.Name)2668          break;2669 2670      if (FAI >= NParameters) {2671        return Error(IDLoc, "parameter named '" + FA.Name +2672                                "' does not exist for macro '" + M->Name + "'");2673      }2674      PI = FAI;2675    }2676    const MCAsmMacroParameter *MP = nullptr;2677    if (M && PI < NParameters)2678      MP = &M->Parameters[PI];2679 2680    SMLoc StrLoc = Lexer.getLoc();2681    SMLoc EndLoc;2682    if (Lexer.is(AsmToken::Percent)) {2683      const MCExpr *AbsoluteExp;2684      int64_t Value;2685      /// Eat '%'.2686      Lex();2687      if (parseExpression(AbsoluteExp, EndLoc))2688        return false;2689      if (!AbsoluteExp->evaluateAsAbsolute(Value,2690                                           getStreamer().getAssemblerPtr()))2691        return Error(StrLoc, "expected absolute expression");2692      const char *StrChar = StrLoc.getPointer();2693      const char *EndChar = EndLoc.getPointer();2694      AsmToken newToken(AsmToken::Integer,2695                        StringRef(StrChar, EndChar - StrChar), Value);2696      FA.Value.push_back(newToken);2697    } else if (parseMacroArgument(MP, FA.Value, EndTok)) {2698      if (M)2699        return addErrorSuffix(" in '" + M->Name + "' macro");2700      else2701        return true;2702    }2703 2704    if (!FA.Value.empty()) {2705      if (A.size() <= PI)2706        A.resize(PI + 1);2707      A[PI] = FA.Value;2708 2709      if (FALocs.size() <= PI)2710        FALocs.resize(PI + 1);2711 2712      FALocs[PI] = Lexer.getLoc();2713    }2714 2715    // At the end of the statement, fill in remaining arguments that have2716    // default values. If there aren't any, then the next argument is2717    // required but missing2718    if (Lexer.is(EndTok)) {2719      bool Failure = false;2720      for (unsigned FAI = 0; FAI < NParameters; ++FAI) {2721        if (A[FAI].empty()) {2722          if (M->Parameters[FAI].Required) {2723            Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),2724                  "missing value for required parameter "2725                  "'" +2726                      M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");2727            Failure = true;2728          }2729 2730          if (!M->Parameters[FAI].Value.empty())2731            A[FAI] = M->Parameters[FAI].Value;2732        }2733      }2734      return Failure;2735    }2736 2737    if (Lexer.is(AsmToken::Comma))2738      Lex();2739  }2740 2741  return TokError("too many positional arguments");2742}2743 2744bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc,2745                                  AsmToken::TokenKind ArgumentEndTok) {2746  // Arbitrarily limit macro nesting depth (default matches 'as'). We can2747  // eliminate this, although we should protect against infinite loops.2748  unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;2749  if (ActiveMacros.size() == MaxNestingDepth) {2750    std::ostringstream MaxNestingDepthError;2751    MaxNestingDepthError << "macros cannot be nested more than "2752                         << MaxNestingDepth << " levels deep."2753                         << " Use -asm-macro-max-nesting-depth to increase "2754                            "this limit.";2755    return TokError(MaxNestingDepthError.str());2756  }2757 2758  MCAsmMacroArguments A;2759  if (parseMacroArguments(M, A, ArgumentEndTok) || parseToken(ArgumentEndTok))2760    return true;2761 2762  // Macro instantiation is lexical, unfortunately. We construct a new buffer2763  // to hold the macro body with substitutions.2764  SmallString<256> Buf;2765  StringRef Body = M->Body;2766  raw_svector_ostream OS(Buf);2767 2768  if (expandMacro(OS, Body, M->Parameters, A, M->Locals, getTok().getLoc()))2769    return true;2770 2771  // We include the endm in the buffer as our cue to exit the macro2772  // instantiation.2773  OS << "endm\n";2774 2775  std::unique_ptr<MemoryBuffer> Instantiation =2776      MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");2777 2778  // Create the macro instantiation object and add to the current macro2779  // instantiation stack.2780  MacroInstantiation *MI = new MacroInstantiation{2781      NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()};2782  ActiveMacros.push_back(MI);2783 2784  ++NumOfMacroInstantiations;2785 2786  // Jump to the macro instantiation and prime the lexer.2787  CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());2788  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());2789  EndStatementAtEOFStack.push_back(true);2790  Lex();2791 2792  return false;2793}2794 2795void MasmParser::handleMacroExit() {2796  // Jump to the token we should return to, and consume it.2797  EndStatementAtEOFStack.pop_back();2798  jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer,2799            EndStatementAtEOFStack.back());2800  Lex();2801 2802  // Pop the instantiation entry.2803  delete ActiveMacros.back();2804  ActiveMacros.pop_back();2805}2806 2807bool MasmParser::handleMacroInvocation(const MCAsmMacro *M, SMLoc NameLoc) {2808  if (!M->IsFunction)2809    return Error(NameLoc, "cannot invoke macro procedure as function");2810 2811  if (parseToken(AsmToken::LParen, "invoking macro function '" + M->Name +2812                                       "' requires arguments in parentheses") ||2813      handleMacroEntry(M, NameLoc, AsmToken::RParen))2814    return true;2815 2816  // Parse all statements in the macro, retrieving the exit value when it ends.2817  std::string ExitValue;2818  SmallVector<AsmRewrite, 4> AsmStrRewrites;2819  while (Lexer.isNot(AsmToken::Eof)) {2820    ParseStatementInfo Info(&AsmStrRewrites);2821    bool HasError = parseStatement(Info, nullptr);2822 2823    if (!HasError && Info.ExitValue) {2824      ExitValue = std::move(*Info.ExitValue);2825      break;2826    }2827 2828    // If we have a Lexer Error we are on an Error Token. Load in Lexer Error2829    // for printing ErrMsg via Lex() only if no (presumably better) parser error2830    // exists.2831    if (HasError && !hasPendingError() && Lexer.getTok().is(AsmToken::Error))2832      Lex();2833 2834    // parseStatement returned true so may need to emit an error.2835    printPendingErrors();2836 2837    // Skipping to the next line if needed.2838    if (HasError && !getLexer().justConsumedEOL())2839      eatToEndOfStatement();2840  }2841 2842  // Exit values may require lexing, unfortunately. We construct a new buffer to2843  // hold the exit value.2844  std::unique_ptr<MemoryBuffer> MacroValue =2845      MemoryBuffer::getMemBufferCopy(ExitValue, "<macro-value>");2846 2847  // Jump from this location to the instantiated exit value, and prime the2848  // lexer.2849  CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(MacroValue), Lexer.getLoc());2850  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,2851                  /*EndStatementAtEOF=*/false);2852  EndStatementAtEOFStack.push_back(false);2853  Lex();2854 2855  return false;2856}2857 2858/// parseIdentifier:2859///   ::= identifier2860///   ::= string2861bool MasmParser::parseIdentifier(StringRef &Res,2862                                 IdentifierPositionKind Position) {2863  // The assembler has relaxed rules for accepting identifiers, in particular we2864  // allow things like '.globl $foo' and '.def @feat.00', which would normally2865  // be separate tokens. At this level, we have already lexed so we cannot2866  // (currently) handle this as a context dependent token, instead we detect2867  // adjacent tokens and return the combined identifier.2868  if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {2869    SMLoc PrefixLoc = getLexer().getLoc();2870 2871    // Consume the prefix character, and check for a following identifier.2872 2873    AsmToken nextTok = peekTok(false);2874 2875    if (nextTok.isNot(AsmToken::Identifier))2876      return true;2877 2878    // We have a '$' or '@' followed by an identifier, make sure they are adjacent.2879    if (PrefixLoc.getPointer() + 1 != nextTok.getLoc().getPointer())2880      return true;2881 2882    // eat $ or @2883    Lexer.Lex(); // Lexer's Lex guarantees consecutive token.2884    // Construct the joined identifier and consume the token.2885    Res =2886        StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);2887    Lex(); // Parser Lex to maintain invariants.2888    return false;2889  }2890 2891  if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String))2892    return true;2893 2894  Res = getTok().getIdentifier();2895 2896  // Consume the identifier token - but if parsing certain directives, avoid2897  // lexical expansion of the next token.2898  ExpandKind ExpandNextToken = ExpandMacros;2899  if (Position == StartOfStatement &&2900      StringSwitch<bool>(Res)2901          .CaseLower("echo", true)2902          .CasesLower({"ifdef", "ifndef", "elseifdef", "elseifndef"}, true)2903          .Default(false)) {2904    ExpandNextToken = DoNotExpandMacros;2905  }2906  Lex(ExpandNextToken);2907 2908  return false;2909}2910 2911/// parseDirectiveEquate:2912///  ::= name "=" expression2913///    | name "equ" expression    (not redefinable)2914///    | name "equ" text-list2915///    | name "textequ" text-list (redefinability unspecified)2916bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,2917                                      DirectiveKind DirKind, SMLoc NameLoc) {2918  auto BuiltinIt = BuiltinSymbolMap.find(Name.lower());2919  if (BuiltinIt != BuiltinSymbolMap.end())2920    return Error(NameLoc, "cannot redefine a built-in symbol");2921 2922  Variable &Var = Variables[Name.lower()];2923  if (Var.Name.empty()) {2924    Var.Name = Name;2925  }2926 2927  SMLoc StartLoc = Lexer.getLoc();2928  if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {2929    // "equ" and "textequ" both allow text expressions.2930    std::string Value;2931    std::string TextItem;2932    if (!parseTextItem(TextItem)) {2933      Value += TextItem;2934 2935      // Accept a text-list, not just one text-item.2936      auto parseItem = [&]() -> bool {2937        if (parseTextItem(TextItem))2938          return TokError("expected text item");2939        Value += TextItem;2940        return false;2941      };2942      if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem))2943        return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");2944 2945      if (!Var.IsText || Var.TextValue != Value) {2946        switch (Var.Redefinable) {2947        case Variable::NOT_REDEFINABLE:2948          return Error(getTok().getLoc(), "invalid variable redefinition");2949        case Variable::WARN_ON_REDEFINITION:2950          if (Warning(NameLoc, "redefining '" + Name +2951                                   "', already defined on the command line")) {2952            return true;2953          }2954          break;2955        default:2956          break;2957        }2958      }2959      Var.IsText = true;2960      Var.TextValue = Value;2961      Var.Redefinable = Variable::REDEFINABLE;2962 2963      return false;2964    }2965  }2966  if (DirKind == DK_TEXTEQU)2967    return TokError("expected <text> in '" + Twine(IDVal) + "' directive");2968 2969  // Parse as expression assignment.2970  const MCExpr *Expr;2971  SMLoc EndLoc;2972  if (parseExpression(Expr, EndLoc))2973    return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");2974  StringRef ExprAsString = StringRef(2975      StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());2976 2977  int64_t Value;2978  if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) {2979    if (DirKind == DK_ASSIGN)2980      return Error(2981          StartLoc,2982          "expected absolute expression; not all symbols have known values",2983          {StartLoc, EndLoc});2984 2985    // Not an absolute expression; define as a text replacement.2986    if (!Var.IsText || Var.TextValue != ExprAsString) {2987      switch (Var.Redefinable) {2988      case Variable::NOT_REDEFINABLE:2989        return Error(getTok().getLoc(), "invalid variable redefinition");2990      case Variable::WARN_ON_REDEFINITION:2991        if (Warning(NameLoc, "redefining '" + Name +2992                                 "', already defined on the command line")) {2993          return true;2994        }2995        break;2996      default:2997        break;2998      }2999    }3000 3001    Var.IsText = true;3002    Var.TextValue = ExprAsString.str();3003    Var.Redefinable = Variable::REDEFINABLE;3004 3005    return false;3006  }3007 3008  auto *Sym = static_cast<MCSymbolCOFF *>(getContext().parseSymbol(Var.Name));3009  const MCConstantExpr *PrevValue =3010      Sym->isVariable()3011          ? dyn_cast_or_null<MCConstantExpr>(Sym->getVariableValue())3012          : nullptr;3013  if (Var.IsText || !PrevValue || PrevValue->getValue() != Value) {3014    switch (Var.Redefinable) {3015    case Variable::NOT_REDEFINABLE:3016      return Error(getTok().getLoc(), "invalid variable redefinition");3017    case Variable::WARN_ON_REDEFINITION:3018      if (Warning(NameLoc, "redefining '" + Name +3019                               "', already defined on the command line")) {3020        return true;3021      }3022      break;3023    default:3024      break;3025    }3026  }3027 3028  Var.IsText = false;3029  Var.TextValue.clear();3030  Var.Redefinable = (DirKind == DK_ASSIGN) ? Variable::REDEFINABLE3031                                           : Variable::NOT_REDEFINABLE;3032 3033  Sym->setRedefinable(Var.Redefinable != Variable::NOT_REDEFINABLE);3034  Sym->setVariableValue(Expr);3035  Sym->setExternal(false);3036 3037  return false;3038}3039 3040bool MasmParser::parseEscapedString(std::string &Data) {3041  if (check(getTok().isNot(AsmToken::String), "expected string"))3042    return true;3043 3044  Data = "";3045  char Quote = getTok().getString().front();3046  StringRef Str = getTok().getStringContents();3047  Data.reserve(Str.size());3048  for (size_t i = 0, e = Str.size(); i != e; ++i) {3049    Data.push_back(Str[i]);3050    if (Str[i] == Quote) {3051      // MASM treats doubled delimiting quotes as an escaped delimiting quote.3052      // If we're escaping the string's trailing delimiter, we're definitely3053      // missing a quotation mark.3054      if (i + 1 == Str.size())3055        return Error(getTok().getLoc(), "missing quotation mark in string");3056      if (Str[i + 1] == Quote)3057        ++i;3058    }3059  }3060 3061  Lex();3062  return false;3063}3064 3065bool MasmParser::parseAngleBracketString(std::string &Data) {3066  SMLoc EndLoc, StartLoc = getTok().getLoc();3067  if (isAngleBracketString(StartLoc, EndLoc)) {3068    const char *StartChar = StartLoc.getPointer() + 1;3069    const char *EndChar = EndLoc.getPointer() - 1;3070    jumpToLoc(EndLoc, CurBuffer, EndStatementAtEOFStack.back());3071    // Eat from '<' to '>'.3072    Lex();3073 3074    Data = angleBracketString(StringRef(StartChar, EndChar - StartChar));3075    return false;3076  }3077  return true;3078}3079 3080/// textItem ::= textLiteral | textMacroID | % constExpr3081bool MasmParser::parseTextItem(std::string &Data) {3082  switch (getTok().getKind()) {3083  default:3084    return true;3085  case AsmToken::Percent: {3086    int64_t Res;3087    if (parseToken(AsmToken::Percent) || parseAbsoluteExpression(Res))3088      return true;3089    Data = std::to_string(Res);3090    return false;3091  }3092  case AsmToken::Less:3093  case AsmToken::LessEqual:3094  case AsmToken::LessLess:3095  case AsmToken::LessGreater:3096    return parseAngleBracketString(Data);3097  case AsmToken::Identifier: {3098    // This must be a text macro; we need to expand it accordingly.3099    StringRef ID;3100    SMLoc StartLoc = getTok().getLoc();3101    if (parseIdentifier(ID))3102      return true;3103    Data = ID.str();3104 3105    bool Expanded = false;3106    while (true) {3107      // Try to resolve as a built-in text macro3108      auto BuiltinIt = BuiltinSymbolMap.find(ID.lower());3109      if (BuiltinIt != BuiltinSymbolMap.end()) {3110        std::optional<std::string> BuiltinText =3111            evaluateBuiltinTextMacro(BuiltinIt->getValue(), StartLoc);3112        if (!BuiltinText) {3113          // Not a text macro; break without substituting3114          break;3115        }3116        Data = std::move(*BuiltinText);3117        ID = StringRef(Data);3118        Expanded = true;3119        continue;3120      }3121 3122      // Try to resolve as a built-in macro function3123      auto BuiltinFuncIt = BuiltinFunctionMap.find(ID.lower());3124      if (BuiltinFuncIt != BuiltinFunctionMap.end()) {3125        Data.clear();3126        if (evaluateBuiltinMacroFunction(BuiltinFuncIt->getValue(), ID, Data)) {3127          return true;3128        }3129        ID = StringRef(Data);3130        Expanded = true;3131        continue;3132      }3133 3134      // Try to resolve as a variable text macro3135      auto VarIt = Variables.find(ID.lower());3136      if (VarIt != Variables.end()) {3137        const Variable &Var = VarIt->getValue();3138        if (!Var.IsText) {3139          // Not a text macro; break without substituting3140          break;3141        }3142        Data = Var.TextValue;3143        ID = StringRef(Data);3144        Expanded = true;3145        continue;3146      }3147 3148      break;3149    }3150 3151    if (!Expanded) {3152      // Not a text macro; not usable in TextItem context. Since we haven't used3153      // the token, put it back for better error recovery.3154      getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));3155      return true;3156    }3157    return false;3158  }3159  }3160  llvm_unreachable("unhandled token kind");3161}3162 3163/// parseDirectiveAscii:3164///   ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]3165bool MasmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {3166  auto parseOp = [&]() -> bool {3167    std::string Data;3168    if (checkForValidSection() || parseEscapedString(Data))3169      return true;3170    getStreamer().emitBytes(Data);3171    if (ZeroTerminated)3172      getStreamer().emitBytes(StringRef("\0", 1));3173    return false;3174  };3175 3176  if (parseMany(parseOp))3177    return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3178  return false;3179}3180 3181bool MasmParser::emitIntValue(const MCExpr *Value, unsigned Size) {3182  // Special case constant expressions to match code generator.3183  if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {3184    assert(Size <= 8 && "Invalid size");3185    int64_t IntValue = MCE->getValue();3186    if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))3187      return Error(MCE->getLoc(), "out of range literal value");3188    getStreamer().emitIntValue(IntValue, Size);3189  } else {3190    const MCSymbolRefExpr *MSE = dyn_cast<MCSymbolRefExpr>(Value);3191    if (MSE && MSE->getSymbol().getName() == "?") {3192      // ? initializer; treat as 0.3193      getStreamer().emitIntValue(0, Size);3194    } else {3195      getStreamer().emitValue(Value, Size, Value->getLoc());3196    }3197  }3198  return false;3199}3200 3201bool MasmParser::parseScalarInitializer(unsigned Size,3202                                        SmallVectorImpl<const MCExpr *> &Values,3203                                        unsigned StringPadLength) {3204  if (Size == 1 && getTok().is(AsmToken::String)) {3205    std::string Value;3206    if (parseEscapedString(Value))3207      return true;3208    // Treat each character as an initializer.3209    for (const unsigned char CharVal : Value)3210      Values.push_back(MCConstantExpr::create(CharVal, getContext()));3211 3212    // Pad the string with spaces to the specified length.3213    for (size_t i = Value.size(); i < StringPadLength; ++i)3214      Values.push_back(MCConstantExpr::create(' ', getContext()));3215  } else {3216    const MCExpr *Value;3217    if (parseExpression(Value))3218      return true;3219    if (getTok().is(AsmToken::Identifier) &&3220        getTok().getString().equals_insensitive("dup")) {3221      Lex(); // Eat 'dup'.3222      const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3223      if (!MCE)3224        return Error(Value->getLoc(),3225                     "cannot repeat value a non-constant number of times");3226      const int64_t Repetitions = MCE->getValue();3227      if (Repetitions < 0)3228        return Error(Value->getLoc(),3229                     "cannot repeat value a negative number of times");3230 3231      SmallVector<const MCExpr *, 1> DuplicatedValues;3232      if (parseToken(AsmToken::LParen,3233                     "parentheses required for 'dup' contents") ||3234          parseScalarInstList(Size, DuplicatedValues) || parseRParen())3235        return true;3236 3237      for (int i = 0; i < Repetitions; ++i)3238        Values.append(DuplicatedValues.begin(), DuplicatedValues.end());3239    } else {3240      Values.push_back(Value);3241    }3242  }3243  return false;3244}3245 3246bool MasmParser::parseScalarInstList(unsigned Size,3247                                     SmallVectorImpl<const MCExpr *> &Values,3248                                     const AsmToken::TokenKind EndToken) {3249  while (getTok().isNot(EndToken) &&3250         (EndToken != AsmToken::Greater ||3251          getTok().isNot(AsmToken::GreaterGreater))) {3252    parseScalarInitializer(Size, Values);3253 3254    // If we see a comma, continue, and allow line continuation.3255    if (!parseOptionalToken(AsmToken::Comma))3256      break;3257    parseOptionalToken(AsmToken::EndOfStatement);3258  }3259  return false;3260}3261 3262bool MasmParser::emitIntegralValues(unsigned Size, unsigned *Count) {3263  SmallVector<const MCExpr *, 1> Values;3264  if (checkForValidSection() || parseScalarInstList(Size, Values))3265    return true;3266 3267  for (const auto *Value : Values) {3268    emitIntValue(Value, Size);3269  }3270  if (Count)3271    *Count = Values.size();3272  return false;3273}3274 3275// Add a field to the current structure.3276bool MasmParser::addIntegralField(StringRef Name, unsigned Size) {3277  StructInfo &Struct = StructInProgress.back();3278  FieldInfo &Field = Struct.addField(Name, FT_INTEGRAL, Size);3279  IntFieldInfo &IntInfo = Field.Contents.IntInfo;3280 3281  Field.Type = Size;3282 3283  if (parseScalarInstList(Size, IntInfo.Values))3284    return true;3285 3286  Field.SizeOf = Field.Type * IntInfo.Values.size();3287  Field.LengthOf = IntInfo.Values.size();3288  const unsigned FieldEnd = Field.Offset + Field.SizeOf;3289  if (!Struct.IsUnion) {3290    Struct.NextOffset = FieldEnd;3291  }3292  Struct.Size = std::max(Struct.Size, FieldEnd);3293  return false;3294}3295 3296/// parseDirectiveValue3297///  ::= (byte | word | ... ) [ expression (, expression)* ]3298bool MasmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {3299  if (StructInProgress.empty()) {3300    // Initialize data value.3301    if (emitIntegralValues(Size))3302      return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3303  } else if (addIntegralField("", Size)) {3304    return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3305  }3306 3307  return false;3308}3309 3310/// parseDirectiveNamedValue3311///  ::= name (byte | word | ... ) [ expression (, expression)* ]3312bool MasmParser::parseDirectiveNamedValue(StringRef TypeName, unsigned Size,3313                                          StringRef Name, SMLoc NameLoc) {3314  if (StructInProgress.empty()) {3315    // Initialize named data value.3316    MCSymbol *Sym = getContext().parseSymbol(Name);3317    getStreamer().emitLabel(Sym);3318    unsigned Count;3319    if (emitIntegralValues(Size, &Count))3320      return addErrorSuffix(" in '" + Twine(TypeName) + "' directive");3321 3322    AsmTypeInfo Type;3323    Type.Name = TypeName;3324    Type.Size = Size * Count;3325    Type.ElementSize = Size;3326    Type.Length = Count;3327    KnownType[Name.lower()] = Type;3328  } else if (addIntegralField(Name, Size)) {3329    return addErrorSuffix(" in '" + Twine(TypeName) + "' directive");3330  }3331 3332  return false;3333}3334 3335bool MasmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {3336  // We don't truly support arithmetic on floating point expressions, so we3337  // have to manually parse unary prefixes.3338  bool IsNeg = false;3339  SMLoc SignLoc;3340  if (getLexer().is(AsmToken::Minus)) {3341    SignLoc = getLexer().getLoc();3342    Lexer.Lex();3343    IsNeg = true;3344  } else if (getLexer().is(AsmToken::Plus)) {3345    SignLoc = getLexer().getLoc();3346    Lexer.Lex();3347  }3348 3349  if (Lexer.is(AsmToken::Error))3350    return TokError(Lexer.getErr());3351  if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) &&3352      Lexer.isNot(AsmToken::Identifier))3353    return TokError("unexpected token in directive");3354 3355  // Convert to an APFloat.3356  APFloat Value(Semantics);3357  StringRef IDVal = getTok().getString();3358  if (getLexer().is(AsmToken::Identifier)) {3359    if (IDVal.equals_insensitive("infinity") || IDVal.equals_insensitive("inf"))3360      Value = APFloat::getInf(Semantics);3361    else if (IDVal.equals_insensitive("nan"))3362      Value = APFloat::getNaN(Semantics, false, ~0);3363    else if (IDVal.equals_insensitive("?"))3364      Value = APFloat::getZero(Semantics);3365    else3366      return TokError("invalid floating point literal");3367  } else if (IDVal.consume_back("r") || IDVal.consume_back("R")) {3368    // MASM hexadecimal floating-point literal; no APFloat conversion needed.3369    // To match ML64.exe, ignore the initial sign.3370    unsigned SizeInBits = Value.getSizeInBits(Semantics);3371    if (SizeInBits != (IDVal.size() << 2))3372      return TokError("invalid floating point literal");3373 3374    // Consume the numeric token.3375    Lex();3376 3377    Res = APInt(SizeInBits, IDVal, 16);3378    if (SignLoc.isValid())3379      return Warning(SignLoc, "MASM-style hex floats ignore explicit sign");3380    return false;3381  } else if (errorToBool(3382                 Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven)3383                     .takeError())) {3384    return TokError("invalid floating point literal");3385  }3386  if (IsNeg)3387    Value.changeSign();3388 3389  // Consume the numeric token.3390  Lex();3391 3392  Res = Value.bitcastToAPInt();3393 3394  return false;3395}3396 3397bool MasmParser::parseRealInstList(const fltSemantics &Semantics,3398                                   SmallVectorImpl<APInt> &ValuesAsInt,3399                                   const AsmToken::TokenKind EndToken) {3400  while (getTok().isNot(EndToken) ||3401         (EndToken == AsmToken::Greater &&3402          getTok().isNot(AsmToken::GreaterGreater))) {3403    const AsmToken NextTok = peekTok();3404    if (NextTok.is(AsmToken::Identifier) &&3405        NextTok.getString().equals_insensitive("dup")) {3406      const MCExpr *Value;3407      if (parseExpression(Value) || parseToken(AsmToken::Identifier))3408        return true;3409      const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3410      if (!MCE)3411        return Error(Value->getLoc(),3412                     "cannot repeat value a non-constant number of times");3413      const int64_t Repetitions = MCE->getValue();3414      if (Repetitions < 0)3415        return Error(Value->getLoc(),3416                     "cannot repeat value a negative number of times");3417 3418      SmallVector<APInt, 1> DuplicatedValues;3419      if (parseToken(AsmToken::LParen,3420                     "parentheses required for 'dup' contents") ||3421          parseRealInstList(Semantics, DuplicatedValues) || parseRParen())3422        return true;3423 3424      for (int i = 0; i < Repetitions; ++i)3425        ValuesAsInt.append(DuplicatedValues.begin(), DuplicatedValues.end());3426    } else {3427      APInt AsInt;3428      if (parseRealValue(Semantics, AsInt))3429        return true;3430      ValuesAsInt.push_back(AsInt);3431    }3432 3433    // Continue if we see a comma. (Also, allow line continuation.)3434    if (!parseOptionalToken(AsmToken::Comma))3435      break;3436    parseOptionalToken(AsmToken::EndOfStatement);3437  }3438 3439  return false;3440}3441 3442// Initialize real data values.3443bool MasmParser::emitRealValues(const fltSemantics &Semantics,3444                                unsigned *Count) {3445  if (checkForValidSection())3446    return true;3447 3448  SmallVector<APInt, 1> ValuesAsInt;3449  if (parseRealInstList(Semantics, ValuesAsInt))3450    return true;3451 3452  for (const APInt &AsInt : ValuesAsInt) {3453    getStreamer().emitIntValue(AsInt);3454  }3455  if (Count)3456    *Count = ValuesAsInt.size();3457  return false;3458}3459 3460// Add a real field to the current struct.3461bool MasmParser::addRealField(StringRef Name, const fltSemantics &Semantics,3462                              size_t Size) {3463  StructInfo &Struct = StructInProgress.back();3464  FieldInfo &Field = Struct.addField(Name, FT_REAL, Size);3465  RealFieldInfo &RealInfo = Field.Contents.RealInfo;3466 3467  Field.SizeOf = 0;3468 3469  if (parseRealInstList(Semantics, RealInfo.AsIntValues))3470    return true;3471 3472  Field.Type = RealInfo.AsIntValues.back().getBitWidth() / 8;3473  Field.LengthOf = RealInfo.AsIntValues.size();3474  Field.SizeOf = Field.Type * Field.LengthOf;3475 3476  const unsigned FieldEnd = Field.Offset + Field.SizeOf;3477  if (!Struct.IsUnion) {3478    Struct.NextOffset = FieldEnd;3479  }3480  Struct.Size = std::max(Struct.Size, FieldEnd);3481  return false;3482}3483 3484/// parseDirectiveRealValue3485///  ::= (real4 | real8 | real10) [ expression (, expression)* ]3486bool MasmParser::parseDirectiveRealValue(StringRef IDVal,3487                                         const fltSemantics &Semantics,3488                                         size_t Size) {3489  if (StructInProgress.empty()) {3490    // Initialize data value.3491    if (emitRealValues(Semantics))3492      return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3493  } else if (addRealField("", Semantics, Size)) {3494    return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");3495  }3496  return false;3497}3498 3499/// parseDirectiveNamedRealValue3500///  ::= name (real4 | real8 | real10) [ expression (, expression)* ]3501bool MasmParser::parseDirectiveNamedRealValue(StringRef TypeName,3502                                              const fltSemantics &Semantics,3503                                              unsigned Size, StringRef Name,3504                                              SMLoc NameLoc) {3505  if (StructInProgress.empty()) {3506    // Initialize named data value.3507    MCSymbol *Sym = getContext().parseSymbol(Name);3508    getStreamer().emitLabel(Sym);3509    unsigned Count;3510    if (emitRealValues(Semantics, &Count))3511      return addErrorSuffix(" in '" + TypeName + "' directive");3512 3513    AsmTypeInfo Type;3514    Type.Name = TypeName;3515    Type.Size = Size * Count;3516    Type.ElementSize = Size;3517    Type.Length = Count;3518    KnownType[Name.lower()] = Type;3519  } else if (addRealField(Name, Semantics, Size)) {3520    return addErrorSuffix(" in '" + TypeName + "' directive");3521  }3522  return false;3523}3524 3525bool MasmParser::parseOptionalAngleBracketOpen() {3526  const AsmToken Tok = getTok();3527  if (parseOptionalToken(AsmToken::LessLess)) {3528    AngleBracketDepth++;3529    Lexer.UnLex(AsmToken(AsmToken::Less, Tok.getString().substr(1)));3530    return true;3531  } else if (parseOptionalToken(AsmToken::LessGreater)) {3532    AngleBracketDepth++;3533    Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1)));3534    return true;3535  } else if (parseOptionalToken(AsmToken::Less)) {3536    AngleBracketDepth++;3537    return true;3538  }3539 3540  return false;3541}3542 3543bool MasmParser::parseAngleBracketClose(const Twine &Msg) {3544  const AsmToken Tok = getTok();3545  if (parseOptionalToken(AsmToken::GreaterGreater)) {3546    Lexer.UnLex(AsmToken(AsmToken::Greater, Tok.getString().substr(1)));3547  } else if (parseToken(AsmToken::Greater, Msg)) {3548    return true;3549  }3550  AngleBracketDepth--;3551  return false;3552}3553 3554bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3555                                       const IntFieldInfo &Contents,3556                                       FieldInitializer &Initializer) {3557  SMLoc Loc = getTok().getLoc();3558 3559  SmallVector<const MCExpr *, 1> Values;3560  if (parseOptionalToken(AsmToken::LCurly)) {3561    if (Field.LengthOf == 1 && Field.Type > 1)3562      return Error(Loc, "Cannot initialize scalar field with array value");3563    if (parseScalarInstList(Field.Type, Values, AsmToken::RCurly) ||3564        parseToken(AsmToken::RCurly))3565      return true;3566  } else if (parseOptionalAngleBracketOpen()) {3567    if (Field.LengthOf == 1 && Field.Type > 1)3568      return Error(Loc, "Cannot initialize scalar field with array value");3569    if (parseScalarInstList(Field.Type, Values, AsmToken::Greater) ||3570        parseAngleBracketClose())3571      return true;3572  } else if (Field.LengthOf > 1 && Field.Type > 1) {3573    return Error(Loc, "Cannot initialize array field with scalar value");3574  } else if (parseScalarInitializer(Field.Type, Values,3575                                    /*StringPadLength=*/Field.LengthOf)) {3576    return true;3577  }3578 3579  if (Values.size() > Field.LengthOf) {3580    return Error(Loc, "Initializer too long for field; expected at most " +3581                          std::to_string(Field.LengthOf) + " elements, got " +3582                          std::to_string(Values.size()));3583  }3584  // Default-initialize all remaining values.3585  Values.append(Contents.Values.begin() + Values.size(), Contents.Values.end());3586 3587  Initializer = FieldInitializer(std::move(Values));3588  return false;3589}3590 3591bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3592                                       const RealFieldInfo &Contents,3593                                       FieldInitializer &Initializer) {3594  const fltSemantics *Semantics;3595  switch (Field.Type) {3596  case 4:3597    Semantics = &APFloat::IEEEsingle();3598    break;3599  case 8:3600    Semantics = &APFloat::IEEEdouble();3601    break;3602  case 10:3603    Semantics = &APFloat::x87DoubleExtended();3604    break;3605  default:3606    llvm_unreachable("unknown real field type");3607  }3608 3609  SMLoc Loc = getTok().getLoc();3610 3611  SmallVector<APInt, 1> AsIntValues;3612  if (parseOptionalToken(AsmToken::LCurly)) {3613    if (Field.LengthOf == 1)3614      return Error(Loc, "Cannot initialize scalar field with array value");3615    if (parseRealInstList(*Semantics, AsIntValues, AsmToken::RCurly) ||3616        parseToken(AsmToken::RCurly))3617      return true;3618  } else if (parseOptionalAngleBracketOpen()) {3619    if (Field.LengthOf == 1)3620      return Error(Loc, "Cannot initialize scalar field with array value");3621    if (parseRealInstList(*Semantics, AsIntValues, AsmToken::Greater) ||3622        parseAngleBracketClose())3623      return true;3624  } else if (Field.LengthOf > 1) {3625    return Error(Loc, "Cannot initialize array field with scalar value");3626  } else {3627    AsIntValues.emplace_back();3628    if (parseRealValue(*Semantics, AsIntValues.back()))3629      return true;3630  }3631 3632  if (AsIntValues.size() > Field.LengthOf) {3633    return Error(Loc, "Initializer too long for field; expected at most " +3634                          std::to_string(Field.LengthOf) + " elements, got " +3635                          std::to_string(AsIntValues.size()));3636  }3637  // Default-initialize all remaining values.3638  AsIntValues.append(Contents.AsIntValues.begin() + AsIntValues.size(),3639                     Contents.AsIntValues.end());3640 3641  Initializer = FieldInitializer(std::move(AsIntValues));3642  return false;3643}3644 3645bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3646                                       const StructFieldInfo &Contents,3647                                       FieldInitializer &Initializer) {3648  SMLoc Loc = getTok().getLoc();3649 3650  std::vector<StructInitializer> Initializers;3651  if (Field.LengthOf > 1) {3652    if (parseOptionalToken(AsmToken::LCurly)) {3653      if (parseStructInstList(Contents.Structure, Initializers,3654                              AsmToken::RCurly) ||3655          parseToken(AsmToken::RCurly))3656        return true;3657    } else if (parseOptionalAngleBracketOpen()) {3658      if (parseStructInstList(Contents.Structure, Initializers,3659                              AsmToken::Greater) ||3660          parseAngleBracketClose())3661        return true;3662    } else {3663      return Error(Loc, "Cannot initialize array field with scalar value");3664    }3665  } else {3666    Initializers.emplace_back();3667    if (parseStructInitializer(Contents.Structure, Initializers.back()))3668      return true;3669  }3670 3671  if (Initializers.size() > Field.LengthOf) {3672    return Error(Loc, "Initializer too long for field; expected at most " +3673                          std::to_string(Field.LengthOf) + " elements, got " +3674                          std::to_string(Initializers.size()));3675  }3676  // Default-initialize all remaining values.3677  llvm::append_range(Initializers, llvm::drop_begin(Contents.Initializers,3678                                                    Initializers.size()));3679 3680  Initializer = FieldInitializer(std::move(Initializers), Contents.Structure);3681  return false;3682}3683 3684bool MasmParser::parseFieldInitializer(const FieldInfo &Field,3685                                       FieldInitializer &Initializer) {3686  switch (Field.Contents.FT) {3687  case FT_INTEGRAL:3688    return parseFieldInitializer(Field, Field.Contents.IntInfo, Initializer);3689  case FT_REAL:3690    return parseFieldInitializer(Field, Field.Contents.RealInfo, Initializer);3691  case FT_STRUCT:3692    return parseFieldInitializer(Field, Field.Contents.StructInfo, Initializer);3693  }3694  llvm_unreachable("Unhandled FieldType enum");3695}3696 3697bool MasmParser::parseStructInitializer(const StructInfo &Structure,3698                                        StructInitializer &Initializer) {3699  const AsmToken FirstToken = getTok();3700 3701  std::optional<AsmToken::TokenKind> EndToken;3702  if (parseOptionalToken(AsmToken::LCurly)) {3703    EndToken = AsmToken::RCurly;3704  } else if (parseOptionalAngleBracketOpen()) {3705    EndToken = AsmToken::Greater;3706    AngleBracketDepth++;3707  } else if (FirstToken.is(AsmToken::Identifier) &&3708             FirstToken.getString() == "?") {3709    // ? initializer; leave EndToken uninitialized to treat as empty.3710    if (parseToken(AsmToken::Identifier))3711      return true;3712  } else {3713    return Error(FirstToken.getLoc(), "Expected struct initializer");3714  }3715 3716  auto &FieldInitializers = Initializer.FieldInitializers;3717  size_t FieldIndex = 0;3718  if (EndToken) {3719    // Initialize all fields with given initializers.3720    while (getTok().isNot(*EndToken) && FieldIndex < Structure.Fields.size()) {3721      const FieldInfo &Field = Structure.Fields[FieldIndex++];3722      if (parseOptionalToken(AsmToken::Comma)) {3723        // Empty initializer; use the default and continue. (Also, allow line3724        // continuation.)3725        FieldInitializers.push_back(Field.Contents);3726        parseOptionalToken(AsmToken::EndOfStatement);3727        continue;3728      }3729      FieldInitializers.emplace_back(Field.Contents.FT);3730      if (parseFieldInitializer(Field, FieldInitializers.back()))3731        return true;3732 3733      // Continue if we see a comma. (Also, allow line continuation.)3734      SMLoc CommaLoc = getTok().getLoc();3735      if (!parseOptionalToken(AsmToken::Comma))3736        break;3737      if (FieldIndex == Structure.Fields.size())3738        return Error(CommaLoc, "'" + Structure.Name +3739                                   "' initializer initializes too many fields");3740      parseOptionalToken(AsmToken::EndOfStatement);3741    }3742  }3743  // Default-initialize all remaining fields.3744  for (const FieldInfo &Field : llvm::drop_begin(Structure.Fields, FieldIndex))3745    FieldInitializers.push_back(Field.Contents);3746 3747  if (EndToken) {3748    if (*EndToken == AsmToken::Greater)3749      return parseAngleBracketClose();3750 3751    return parseToken(*EndToken);3752  }3753 3754  return false;3755}3756 3757bool MasmParser::parseStructInstList(3758    const StructInfo &Structure, std::vector<StructInitializer> &Initializers,3759    const AsmToken::TokenKind EndToken) {3760  while (getTok().isNot(EndToken) ||3761         (EndToken == AsmToken::Greater &&3762          getTok().isNot(AsmToken::GreaterGreater))) {3763    const AsmToken NextTok = peekTok();3764    if (NextTok.is(AsmToken::Identifier) &&3765        NextTok.getString().equals_insensitive("dup")) {3766      const MCExpr *Value;3767      if (parseExpression(Value) || parseToken(AsmToken::Identifier))3768        return true;3769      const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);3770      if (!MCE)3771        return Error(Value->getLoc(),3772                     "cannot repeat value a non-constant number of times");3773      const int64_t Repetitions = MCE->getValue();3774      if (Repetitions < 0)3775        return Error(Value->getLoc(),3776                     "cannot repeat value a negative number of times");3777 3778      std::vector<StructInitializer> DuplicatedValues;3779      if (parseToken(AsmToken::LParen,3780                     "parentheses required for 'dup' contents") ||3781          parseStructInstList(Structure, DuplicatedValues) || parseRParen())3782        return true;3783 3784      for (int i = 0; i < Repetitions; ++i)3785        llvm::append_range(Initializers, DuplicatedValues);3786    } else {3787      Initializers.emplace_back();3788      if (parseStructInitializer(Structure, Initializers.back()))3789        return true;3790    }3791 3792    // Continue if we see a comma. (Also, allow line continuation.)3793    if (!parseOptionalToken(AsmToken::Comma))3794      break;3795    parseOptionalToken(AsmToken::EndOfStatement);3796  }3797 3798  return false;3799}3800 3801bool MasmParser::emitFieldValue(const FieldInfo &Field,3802                                const IntFieldInfo &Contents) {3803  // Default-initialize all values.3804  for (const MCExpr *Value : Contents.Values) {3805    if (emitIntValue(Value, Field.Type))3806      return true;3807  }3808  return false;3809}3810 3811bool MasmParser::emitFieldValue(const FieldInfo &Field,3812                                const RealFieldInfo &Contents) {3813  for (const APInt &AsInt : Contents.AsIntValues) {3814    getStreamer().emitIntValue(AsInt.getLimitedValue(),3815                               AsInt.getBitWidth() / 8);3816  }3817  return false;3818}3819 3820bool MasmParser::emitFieldValue(const FieldInfo &Field,3821                                const StructFieldInfo &Contents) {3822  for (const auto &Initializer : Contents.Initializers) {3823    size_t Index = 0, Offset = 0;3824    for (const auto &SubField : Contents.Structure.Fields) {3825      getStreamer().emitZeros(SubField.Offset - Offset);3826      Offset = SubField.Offset + SubField.SizeOf;3827      emitFieldInitializer(SubField, Initializer.FieldInitializers[Index++]);3828    }3829  }3830  return false;3831}3832 3833bool MasmParser::emitFieldValue(const FieldInfo &Field) {3834  switch (Field.Contents.FT) {3835  case FT_INTEGRAL:3836    return emitFieldValue(Field, Field.Contents.IntInfo);3837  case FT_REAL:3838    return emitFieldValue(Field, Field.Contents.RealInfo);3839  case FT_STRUCT:3840    return emitFieldValue(Field, Field.Contents.StructInfo);3841  }3842  llvm_unreachable("Unhandled FieldType enum");3843}3844 3845bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3846                                      const IntFieldInfo &Contents,3847                                      const IntFieldInfo &Initializer) {3848  for (const auto &Value : Initializer.Values) {3849    if (emitIntValue(Value, Field.Type))3850      return true;3851  }3852  // Default-initialize all remaining values.3853  for (const auto &Value :3854           llvm::drop_begin(Contents.Values, Initializer.Values.size())) {3855    if (emitIntValue(Value, Field.Type))3856      return true;3857  }3858  return false;3859}3860 3861bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3862                                      const RealFieldInfo &Contents,3863                                      const RealFieldInfo &Initializer) {3864  for (const auto &AsInt : Initializer.AsIntValues) {3865    getStreamer().emitIntValue(AsInt.getLimitedValue(),3866                               AsInt.getBitWidth() / 8);3867  }3868  // Default-initialize all remaining values.3869  for (const auto &AsInt :3870       llvm::drop_begin(Contents.AsIntValues, Initializer.AsIntValues.size())) {3871    getStreamer().emitIntValue(AsInt.getLimitedValue(),3872                               AsInt.getBitWidth() / 8);3873  }3874  return false;3875}3876 3877bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3878                                      const StructFieldInfo &Contents,3879                                      const StructFieldInfo &Initializer) {3880  for (const auto &Init : Initializer.Initializers) {3881    if (emitStructInitializer(Contents.Structure, Init))3882      return true;3883  }3884  // Default-initialize all remaining values.3885  for (const auto &Init : llvm::drop_begin(Contents.Initializers,3886                                           Initializer.Initializers.size())) {3887    if (emitStructInitializer(Contents.Structure, Init))3888      return true;3889  }3890  return false;3891}3892 3893bool MasmParser::emitFieldInitializer(const FieldInfo &Field,3894                                      const FieldInitializer &Initializer) {3895  switch (Field.Contents.FT) {3896  case FT_INTEGRAL:3897    return emitFieldInitializer(Field, Field.Contents.IntInfo,3898                                Initializer.IntInfo);3899  case FT_REAL:3900    return emitFieldInitializer(Field, Field.Contents.RealInfo,3901                                Initializer.RealInfo);3902  case FT_STRUCT:3903    return emitFieldInitializer(Field, Field.Contents.StructInfo,3904                                Initializer.StructInfo);3905  }3906  llvm_unreachable("Unhandled FieldType enum");3907}3908 3909bool MasmParser::emitStructInitializer(const StructInfo &Structure,3910                                       const StructInitializer &Initializer) {3911  if (!Structure.Initializable)3912    return Error(getLexer().getLoc(),3913                 "cannot initialize a value of type '" + Structure.Name +3914                     "'; 'org' was used in the type's declaration");3915  size_t Index = 0, Offset = 0;3916  for (const auto &Init : Initializer.FieldInitializers) {3917    const auto &Field = Structure.Fields[Index++];3918    getStreamer().emitZeros(Field.Offset - Offset);3919    Offset = Field.Offset + Field.SizeOf;3920    if (emitFieldInitializer(Field, Init))3921      return true;3922  }3923  // Default-initialize all remaining fields.3924  for (const auto &Field : llvm::drop_begin(3925           Structure.Fields, Initializer.FieldInitializers.size())) {3926    getStreamer().emitZeros(Field.Offset - Offset);3927    Offset = Field.Offset + Field.SizeOf;3928    if (emitFieldValue(Field))3929      return true;3930  }3931  // Add final padding.3932  if (Offset != Structure.Size)3933    getStreamer().emitZeros(Structure.Size - Offset);3934  return false;3935}3936 3937// Set data values from initializers.3938bool MasmParser::emitStructValues(const StructInfo &Structure,3939                                  unsigned *Count) {3940  std::vector<StructInitializer> Initializers;3941  if (parseStructInstList(Structure, Initializers))3942    return true;3943 3944  for (const auto &Initializer : Initializers) {3945    if (emitStructInitializer(Structure, Initializer))3946      return true;3947  }3948 3949  if (Count)3950    *Count = Initializers.size();3951  return false;3952}3953 3954// Declare a field in the current struct.3955bool MasmParser::addStructField(StringRef Name, const StructInfo &Structure) {3956  StructInfo &OwningStruct = StructInProgress.back();3957  FieldInfo &Field =3958      OwningStruct.addField(Name, FT_STRUCT, Structure.AlignmentSize);3959  StructFieldInfo &StructInfo = Field.Contents.StructInfo;3960 3961  StructInfo.Structure = Structure;3962  Field.Type = Structure.Size;3963 3964  if (parseStructInstList(Structure, StructInfo.Initializers))3965    return true;3966 3967  Field.LengthOf = StructInfo.Initializers.size();3968  Field.SizeOf = Field.Type * Field.LengthOf;3969 3970  const unsigned FieldEnd = Field.Offset + Field.SizeOf;3971  if (!OwningStruct.IsUnion) {3972    OwningStruct.NextOffset = FieldEnd;3973  }3974  OwningStruct.Size = std::max(OwningStruct.Size, FieldEnd);3975 3976  return false;3977}3978 3979/// parseDirectiveStructValue3980///  ::= struct-id (<struct-initializer> | {struct-initializer})3981///                [, (<struct-initializer> | {struct-initializer})]*3982bool MasmParser::parseDirectiveStructValue(const StructInfo &Structure,3983                                           StringRef Directive, SMLoc DirLoc) {3984  if (StructInProgress.empty()) {3985    if (emitStructValues(Structure))3986      return true;3987  } else if (addStructField("", Structure)) {3988    return addErrorSuffix(" in '" + Twine(Directive) + "' directive");3989  }3990 3991  return false;3992}3993 3994/// parseDirectiveNamedValue3995///  ::= name (byte | word | ... ) [ expression (, expression)* ]3996bool MasmParser::parseDirectiveNamedStructValue(const StructInfo &Structure,3997                                                StringRef Directive,3998                                                SMLoc DirLoc, StringRef Name) {3999  if (StructInProgress.empty()) {4000    // Initialize named data value.4001    MCSymbol *Sym = getContext().parseSymbol(Name);4002    getStreamer().emitLabel(Sym);4003    unsigned Count;4004    if (emitStructValues(Structure, &Count))4005      return true;4006    AsmTypeInfo Type;4007    Type.Name = Structure.Name;4008    Type.Size = Structure.Size * Count;4009    Type.ElementSize = Structure.Size;4010    Type.Length = Count;4011    KnownType[Name.lower()] = Type;4012  } else if (addStructField(Name, Structure)) {4013    return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4014  }4015 4016  return false;4017}4018 4019/// parseDirectiveStruct4020///  ::= <name> (STRUC | STRUCT | UNION) [fieldAlign] [, NONUNIQUE]4021///      (dataDir | generalDir | offsetDir | nestedStruct)+4022///      <name> ENDS4023////// dataDir = data declaration4024////// offsetDir = EVEN, ORG, ALIGN4025bool MasmParser::parseDirectiveStruct(StringRef Directive,4026                                      DirectiveKind DirKind, StringRef Name,4027                                      SMLoc NameLoc) {4028  // We ignore NONUNIQUE; we do not support OPTION M510 or OPTION OLDSTRUCTS4029  // anyway, so all field accesses must be qualified.4030  AsmToken NextTok = getTok();4031  int64_t AlignmentValue = 1;4032  if (NextTok.isNot(AsmToken::Comma) &&4033      NextTok.isNot(AsmToken::EndOfStatement) &&4034      parseAbsoluteExpression(AlignmentValue)) {4035    return addErrorSuffix(" in alignment value for '" + Twine(Directive) +4036                          "' directive");4037  }4038  if (!isPowerOf2_64(AlignmentValue)) {4039    return Error(NextTok.getLoc(), "alignment must be a power of two; was " +4040                                       std::to_string(AlignmentValue));4041  }4042 4043  StringRef Qualifier;4044  SMLoc QualifierLoc;4045  if (parseOptionalToken(AsmToken::Comma)) {4046    QualifierLoc = getTok().getLoc();4047    if (parseIdentifier(Qualifier))4048      return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4049    if (!Qualifier.equals_insensitive("nonunique"))4050      return Error(QualifierLoc, "Unrecognized qualifier for '" +4051                                     Twine(Directive) +4052                                     "' directive; expected none or NONUNIQUE");4053  }4054 4055  if (parseEOL())4056    return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4057 4058  StructInProgress.emplace_back(Name, DirKind == DK_UNION, AlignmentValue);4059  return false;4060}4061 4062/// parseDirectiveNestedStruct4063///  ::= (STRUC | STRUCT | UNION) [name]4064///      (dataDir | generalDir | offsetDir | nestedStruct)+4065///      ENDS4066bool MasmParser::parseDirectiveNestedStruct(StringRef Directive,4067                                            DirectiveKind DirKind) {4068  if (StructInProgress.empty())4069    return TokError("missing name in top-level '" + Twine(Directive) +4070                    "' directive");4071 4072  StringRef Name;4073  if (getTok().is(AsmToken::Identifier)) {4074    Name = getTok().getIdentifier();4075    parseToken(AsmToken::Identifier);4076  }4077  if (parseEOL())4078    return addErrorSuffix(" in '" + Twine(Directive) + "' directive");4079 4080  // Reserve space to ensure Alignment doesn't get invalidated when4081  // StructInProgress grows.4082  StructInProgress.reserve(StructInProgress.size() + 1);4083  StructInProgress.emplace_back(Name, DirKind == DK_UNION,4084                                StructInProgress.back().Alignment);4085  return false;4086}4087 4088bool MasmParser::parseDirectiveEnds(StringRef Name, SMLoc NameLoc) {4089  if (StructInProgress.empty())4090    return Error(NameLoc, "ENDS directive without matching STRUC/STRUCT/UNION");4091  if (StructInProgress.size() > 1)4092    return Error(NameLoc, "unexpected name in nested ENDS directive");4093  if (StructInProgress.back().Name.compare_insensitive(Name))4094    return Error(NameLoc, "mismatched name in ENDS directive; expected '" +4095                              StructInProgress.back().Name + "'");4096  StructInfo Structure = StructInProgress.pop_back_val();4097  // Pad to make the structure's size divisible by the smaller of its alignment4098  // and the size of its largest field.4099  Structure.Size = llvm::alignTo(4100      Structure.Size, std::min(Structure.Alignment, Structure.AlignmentSize));4101  Structs[Name.lower()] = Structure;4102 4103  if (parseEOL())4104    return addErrorSuffix(" in ENDS directive");4105 4106  return false;4107}4108 4109bool MasmParser::parseDirectiveNestedEnds() {4110  if (StructInProgress.empty())4111    return TokError("ENDS directive without matching STRUC/STRUCT/UNION");4112  if (StructInProgress.size() == 1)4113    return TokError("missing name in top-level ENDS directive");4114 4115  if (parseEOL())4116    return addErrorSuffix(" in nested ENDS directive");4117 4118  StructInfo Structure = StructInProgress.pop_back_val();4119  // Pad to make the structure's size divisible by its alignment.4120  Structure.Size = llvm::alignTo(Structure.Size, Structure.Alignment);4121 4122  StructInfo &ParentStruct = StructInProgress.back();4123  if (Structure.Name.empty()) {4124    // Anonymous substructures' fields are addressed as if they belong to the4125    // parent structure - so we transfer them to the parent here.4126    const size_t OldFields = ParentStruct.Fields.size();4127    ParentStruct.Fields.insert(4128        ParentStruct.Fields.end(),4129        std::make_move_iterator(Structure.Fields.begin()),4130        std::make_move_iterator(Structure.Fields.end()));4131    for (const auto &FieldByName : Structure.FieldsByName) {4132      ParentStruct.FieldsByName[FieldByName.getKey()] =4133          FieldByName.getValue() + OldFields;4134    }4135 4136    unsigned FirstFieldOffset = 0;4137    if (!Structure.Fields.empty() && !ParentStruct.IsUnion) {4138      FirstFieldOffset = llvm::alignTo(4139          ParentStruct.NextOffset,4140          std::min(ParentStruct.Alignment, Structure.AlignmentSize));4141    }4142 4143    if (ParentStruct.IsUnion) {4144      ParentStruct.Size = std::max(ParentStruct.Size, Structure.Size);4145    } else {4146      for (auto &Field : llvm::drop_begin(ParentStruct.Fields, OldFields))4147        Field.Offset += FirstFieldOffset;4148 4149      const unsigned StructureEnd = FirstFieldOffset + Structure.Size;4150      if (!ParentStruct.IsUnion) {4151        ParentStruct.NextOffset = StructureEnd;4152      }4153      ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);4154    }4155  } else {4156    FieldInfo &Field = ParentStruct.addField(Structure.Name, FT_STRUCT,4157                                             Structure.AlignmentSize);4158    StructFieldInfo &StructInfo = Field.Contents.StructInfo;4159    Field.Type = Structure.Size;4160    Field.LengthOf = 1;4161    Field.SizeOf = Structure.Size;4162 4163    const unsigned StructureEnd = Field.Offset + Field.SizeOf;4164    if (!ParentStruct.IsUnion) {4165      ParentStruct.NextOffset = StructureEnd;4166    }4167    ParentStruct.Size = std::max(ParentStruct.Size, StructureEnd);4168 4169    StructInfo.Structure = Structure;4170    StructInfo.Initializers.emplace_back();4171    auto &FieldInitializers = StructInfo.Initializers.back().FieldInitializers;4172    for (const auto &SubField : Structure.Fields) {4173      FieldInitializers.push_back(SubField.Contents);4174    }4175  }4176 4177  return false;4178}4179 4180/// parseDirectiveOrg4181///  ::= org expression4182bool MasmParser::parseDirectiveOrg() {4183  const MCExpr *Offset;4184  SMLoc OffsetLoc = Lexer.getLoc();4185  if (checkForValidSection() || parseExpression(Offset))4186    return true;4187  if (parseEOL())4188    return addErrorSuffix(" in 'org' directive");4189 4190  if (StructInProgress.empty()) {4191    // Not in a struct; change the offset for the next instruction or data4192    if (checkForValidSection())4193      return addErrorSuffix(" in 'org' directive");4194 4195    getStreamer().emitValueToOffset(Offset, 0, OffsetLoc);4196  } else {4197    // Offset the next field of this struct4198    StructInfo &Structure = StructInProgress.back();4199    int64_t OffsetRes;4200    if (!Offset->evaluateAsAbsolute(OffsetRes, getStreamer().getAssemblerPtr()))4201      return Error(OffsetLoc,4202                   "expected absolute expression in 'org' directive");4203    if (OffsetRes < 0)4204      return Error(4205          OffsetLoc,4206          "expected non-negative value in struct's 'org' directive; was " +4207              std::to_string(OffsetRes));4208    Structure.NextOffset = static_cast<unsigned>(OffsetRes);4209 4210    // ORG-affected structures cannot be initialized4211    Structure.Initializable = false;4212  }4213 4214  return false;4215}4216 4217bool MasmParser::emitAlignTo(int64_t Alignment) {4218  if (StructInProgress.empty()) {4219    // Not in a struct; align the next instruction or data4220    if (checkForValidSection())4221      return true;4222 4223    // Check whether we should use optimal code alignment for this align4224    // directive.4225    const MCSection *Section = getStreamer().getCurrentSectionOnly();4226    if (MAI.useCodeAlign(*Section)) {4227      getStreamer().emitCodeAlignment(Align(Alignment),4228                                      &getTargetParser().getSTI(),4229                                      /*MaxBytesToEmit=*/0);4230    } else {4231      // FIXME: Target specific behavior about how the "extra" bytes are filled.4232      getStreamer().emitValueToAlignment(Align(Alignment), /*Value=*/0,4233                                         /*ValueSize=*/1,4234                                         /*MaxBytesToEmit=*/0);4235    }4236  } else {4237    // Align the next field of this struct4238    StructInfo &Structure = StructInProgress.back();4239    Structure.NextOffset = llvm::alignTo(Structure.NextOffset, Alignment);4240  }4241 4242  return false;4243}4244 4245/// parseDirectiveAlign4246///  ::= align expression4247bool MasmParser::parseDirectiveAlign() {4248  SMLoc AlignmentLoc = getLexer().getLoc();4249  int64_t Alignment;4250 4251  // Ignore empty 'align' directives.4252  if (getTok().is(AsmToken::EndOfStatement)) {4253    return Warning(AlignmentLoc,4254                   "align directive with no operand is ignored") &&4255           parseEOL();4256  }4257  if (parseAbsoluteExpression(Alignment) || parseEOL())4258    return addErrorSuffix(" in align directive");4259 4260  // Always emit an alignment here even if we throw an error.4261  bool ReturnVal = false;4262 4263  // Reject alignments that aren't either a power of two or zero, for ML.exe4264  // compatibility. Alignment of zero is silently rounded up to one.4265  if (Alignment == 0)4266    Alignment = 1;4267  if (!isPowerOf2_64(Alignment))4268    ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2; was " +4269                                         std::to_string(Alignment));4270 4271  if (emitAlignTo(Alignment))4272    ReturnVal |= addErrorSuffix(" in align directive");4273 4274  return ReturnVal;4275}4276 4277/// parseDirectiveEven4278///  ::= even4279bool MasmParser::parseDirectiveEven() {4280  if (parseEOL() || emitAlignTo(2))4281    return addErrorSuffix(" in even directive");4282 4283  return false;4284}4285 4286/// parseDirectiveMacro4287/// ::= name macro [parameters]4288///     ["LOCAL" identifiers]4289///   parameters ::= parameter [, parameter]*4290///   parameter ::= name ":" qualifier4291///   qualifier ::= "req" | "vararg" | "=" macro_argument4292bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) {4293  MCAsmMacroParameters Parameters;4294  while (getLexer().isNot(AsmToken::EndOfStatement)) {4295    if (!Parameters.empty() && Parameters.back().Vararg)4296      return Error(Lexer.getLoc(),4297                   "Vararg parameter '" + Parameters.back().Name +4298                       "' should be last in the list of parameters");4299 4300    MCAsmMacroParameter Parameter;4301    if (parseIdentifier(Parameter.Name))4302      return TokError("expected identifier in 'macro' directive");4303 4304    // Emit an error if two (or more) named parameters share the same name.4305    for (const MCAsmMacroParameter& CurrParam : Parameters)4306      if (CurrParam.Name.equals_insensitive(Parameter.Name))4307        return TokError("macro '" + Name + "' has multiple parameters"4308                        " named '" + Parameter.Name + "'");4309 4310    if (Lexer.is(AsmToken::Colon)) {4311      Lex();  // consume ':'4312 4313      if (parseOptionalToken(AsmToken::Equal)) {4314        // Default value4315        SMLoc ParamLoc;4316 4317        ParamLoc = Lexer.getLoc();4318        if (parseMacroArgument(nullptr, Parameter.Value))4319          return true;4320      } else {4321        SMLoc QualLoc;4322        StringRef Qualifier;4323 4324        QualLoc = Lexer.getLoc();4325        if (parseIdentifier(Qualifier))4326          return Error(QualLoc, "missing parameter qualifier for "4327                                "'" +4328                                    Parameter.Name + "' in macro '" + Name +4329                                    "'");4330 4331        if (Qualifier.equals_insensitive("req"))4332          Parameter.Required = true;4333        else if (Qualifier.equals_insensitive("vararg"))4334          Parameter.Vararg = true;4335        else4336          return Error(QualLoc,4337                       Qualifier + " is not a valid parameter qualifier for '" +4338                           Parameter.Name + "' in macro '" + Name + "'");4339      }4340    }4341 4342    Parameters.push_back(std::move(Parameter));4343 4344    if (getLexer().is(AsmToken::Comma))4345      Lex();4346  }4347 4348  // Eat just the end of statement.4349  Lexer.Lex();4350 4351  std::vector<std::string> Locals;4352  if (getTok().is(AsmToken::Identifier) &&4353      getTok().getIdentifier().equals_insensitive("local")) {4354    Lex(); // Eat the LOCAL directive.4355 4356    StringRef ID;4357    while (true) {4358      if (parseIdentifier(ID))4359        return true;4360      Locals.push_back(ID.lower());4361 4362      // If we see a comma, continue (and allow line continuation).4363      if (!parseOptionalToken(AsmToken::Comma))4364        break;4365      parseOptionalToken(AsmToken::EndOfStatement);4366    }4367  }4368 4369  // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors.4370  AsmToken EndToken, StartToken = getTok();4371  unsigned MacroDepth = 0;4372  bool IsMacroFunction = false;4373  // Lex the macro definition.4374  while (true) {4375    // Ignore Lexing errors in macros.4376    while (Lexer.is(AsmToken::Error)) {4377      Lexer.Lex();4378    }4379 4380    // Check whether we have reached the end of the file.4381    if (getLexer().is(AsmToken::Eof))4382      return Error(NameLoc, "no matching 'endm' in definition");4383 4384    // Otherwise, check whether we have reached the 'endm'... and determine if4385    // this is a macro function.4386    if (getLexer().is(AsmToken::Identifier)) {4387      if (getTok().getIdentifier().equals_insensitive("endm")) {4388        if (MacroDepth == 0) { // Outermost macro.4389          EndToken = getTok();4390          Lexer.Lex();4391          if (getLexer().isNot(AsmToken::EndOfStatement))4392            return TokError("unexpected token in '" + EndToken.getIdentifier() +4393                            "' directive");4394          break;4395        } else {4396          // Otherwise we just found the end of an inner macro.4397          --MacroDepth;4398        }4399      } else if (getTok().getIdentifier().equals_insensitive("exitm")) {4400        if (MacroDepth == 0 && peekTok().isNot(AsmToken::EndOfStatement)) {4401          IsMacroFunction = true;4402        }4403      } else if (isMacroLikeDirective()) {4404        // We allow nested macros. Those aren't instantiated until the4405        // outermost macro is expanded so just ignore them for now.4406        ++MacroDepth;4407      }4408    }4409 4410    // Otherwise, scan til the end of the statement.4411    eatToEndOfStatement();4412  }4413 4414  if (getContext().lookupMacro(Name.lower())) {4415    return Error(NameLoc, "macro '" + Name + "' is already defined");4416  }4417 4418  const char *BodyStart = StartToken.getLoc().getPointer();4419  const char *BodyEnd = EndToken.getLoc().getPointer();4420  StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);4421  MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals),4422                   IsMacroFunction);4423  DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";4424                  Macro.dump());4425  getContext().defineMacro(Name.lower(), std::move(Macro));4426  return false;4427}4428 4429/// parseDirectiveExitMacro4430/// ::= "exitm" [textitem]4431bool MasmParser::parseDirectiveExitMacro(SMLoc DirectiveLoc,4432                                         StringRef Directive,4433                                         std::string &Value) {4434  SMLoc EndLoc = getTok().getLoc();4435  if (getTok().isNot(AsmToken::EndOfStatement) && parseTextItem(Value))4436    return Error(EndLoc,4437                 "unable to parse text item in '" + Directive + "' directive");4438  eatToEndOfStatement();4439 4440  if (!isInsideMacroInstantiation())4441    return TokError("unexpected '" + Directive + "' in file, "4442                                                 "no current macro definition");4443 4444  // Exit all conditionals that are active in the current macro.4445  while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {4446    TheCondState = TheCondStack.back();4447    TheCondStack.pop_back();4448  }4449 4450  handleMacroExit();4451  return false;4452}4453 4454/// parseDirectiveEndMacro4455/// ::= endm4456bool MasmParser::parseDirectiveEndMacro(StringRef Directive) {4457  if (getLexer().isNot(AsmToken::EndOfStatement))4458    return TokError("unexpected token in '" + Directive + "' directive");4459 4460  // If we are inside a macro instantiation, terminate the current4461  // instantiation.4462  if (isInsideMacroInstantiation()) {4463    handleMacroExit();4464    return false;4465  }4466 4467  // Otherwise, this .endmacro is a stray entry in the file; well formed4468  // .endmacro directives are handled during the macro definition parsing.4469  return TokError("unexpected '" + Directive + "' in file, "4470                                               "no current macro definition");4471}4472 4473/// parseDirectivePurgeMacro4474/// ::= purge identifier ( , identifier )*4475bool MasmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {4476  StringRef Name;4477  while (true) {4478    SMLoc NameLoc;4479    if (parseTokenLoc(NameLoc) ||4480        check(parseIdentifier(Name), NameLoc,4481              "expected identifier in 'purge' directive"))4482      return true;4483 4484    DEBUG_WITH_TYPE("asm-macros", dbgs()4485                                      << "Un-defining macro: " << Name << "\n");4486    if (!getContext().lookupMacro(Name.lower()))4487      return Error(NameLoc, "macro '" + Name + "' is not defined");4488    getContext().undefineMacro(Name.lower());4489 4490    if (!parseOptionalToken(AsmToken::Comma))4491      break;4492    parseOptionalToken(AsmToken::EndOfStatement);4493  }4494 4495  return false;4496}4497 4498bool MasmParser::parseDirectiveExtern() {4499  // .extern is the default - but we still need to take any provided type info.4500  auto parseOp = [&]() -> bool {4501    MCSymbol *Sym;4502    SMLoc NameLoc = getTok().getLoc();4503    if (parseSymbol(Sym))4504      return Error(NameLoc, "expected name");4505    if (parseToken(AsmToken::Colon))4506      return true;4507 4508    StringRef TypeName;4509    SMLoc TypeLoc = getTok().getLoc();4510    if (parseIdentifier(TypeName))4511      return Error(TypeLoc, "expected type");4512    if (!TypeName.equals_insensitive("proc")) {4513      AsmTypeInfo Type;4514      if (lookUpType(TypeName, Type))4515        return Error(TypeLoc, "unrecognized type");4516      KnownType[Sym->getName().lower()] = Type;4517    }4518 4519    static_cast<MCSymbolCOFF *>(Sym)->setExternal(true);4520    getStreamer().emitSymbolAttribute(Sym, MCSA_Extern);4521 4522    return false;4523  };4524 4525  if (parseMany(parseOp))4526    return addErrorSuffix(" in directive 'extern'");4527  return false;4528}4529 4530/// parseDirectiveSymbolAttribute4531///  ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]4532bool MasmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {4533  auto parseOp = [&]() -> bool {4534    SMLoc Loc = getTok().getLoc();4535    MCSymbol *Sym;4536    if (parseSymbol(Sym))4537      return Error(Loc, "expected identifier");4538 4539    // Assembler local symbols don't make any sense here. Complain loudly.4540    if (Sym->isTemporary())4541      return Error(Loc, "non-local symbol required");4542 4543    if (!getStreamer().emitSymbolAttribute(Sym, Attr))4544      return Error(Loc, "unable to emit symbol attribute");4545    return false;4546  };4547 4548  if (parseMany(parseOp))4549    return addErrorSuffix(" in directive");4550  return false;4551}4552 4553/// parseDirectiveComm4554///  ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]4555bool MasmParser::parseDirectiveComm(bool IsLocal) {4556  if (checkForValidSection())4557    return true;4558 4559  SMLoc IDLoc = getLexer().getLoc();4560  MCSymbol *Sym;4561  if (parseSymbol(Sym))4562    return TokError("expected identifier in directive");4563 4564  if (getLexer().isNot(AsmToken::Comma))4565    return TokError("unexpected token in directive");4566  Lex();4567 4568  int64_t Size;4569  SMLoc SizeLoc = getLexer().getLoc();4570  if (parseAbsoluteExpression(Size))4571    return true;4572 4573  int64_t Pow2Alignment = 0;4574  SMLoc Pow2AlignmentLoc;4575  if (getLexer().is(AsmToken::Comma)) {4576    Lex();4577    Pow2AlignmentLoc = getLexer().getLoc();4578    if (parseAbsoluteExpression(Pow2Alignment))4579      return true;4580 4581    LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();4582    if (IsLocal && LCOMM == LCOMM::NoAlignment)4583      return Error(Pow2AlignmentLoc, "alignment not supported on this target");4584 4585    // If this target takes alignments in bytes (not log) validate and convert.4586    if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||4587        (IsLocal && LCOMM == LCOMM::ByteAlignment)) {4588      if (!isPowerOf2_64(Pow2Alignment))4589        return Error(Pow2AlignmentLoc, "alignment must be a power of 2");4590      Pow2Alignment = Log2_64(Pow2Alignment);4591    }4592  }4593 4594  if (parseEOL())4595    return true;4596 4597  // NOTE: a size of zero for a .comm should create a undefined symbol4598  // but a size of .lcomm creates a bss symbol of size zero.4599  if (Size < 0)4600    return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't "4601                          "be less than zero");4602 4603  // NOTE: The alignment in the directive is a power of 2 value, the assembler4604  // may internally end up wanting an alignment in bytes.4605  // FIXME: Diagnose overflow.4606  if (Pow2Alignment < 0)4607    return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive "4608                                   "alignment, can't be less than zero");4609 4610  Sym->redefineIfPossible();4611  if (!Sym->isUndefined())4612    return Error(IDLoc, "invalid symbol redefinition");4613 4614  // Create the Symbol as a common or local common with Size and Pow2Alignment.4615  if (IsLocal) {4616    getStreamer().emitLocalCommonSymbol(Sym, Size,4617                                        Align(1ULL << Pow2Alignment));4618    return false;4619  }4620 4621  getStreamer().emitCommonSymbol(Sym, Size, Align(1ULL << Pow2Alignment));4622  return false;4623}4624 4625/// parseDirectiveComment4626///  ::= comment delimiter [[text]]4627///              [[text]]4628///              [[text]] delimiter [[text]]4629bool MasmParser::parseDirectiveComment(SMLoc DirectiveLoc) {4630  std::string FirstLine = parseStringTo(AsmToken::EndOfStatement);4631  size_t DelimiterEnd = FirstLine.find_first_of("\b\t\v\f\r\x1A ");4632  assert(DelimiterEnd != std::string::npos);4633  StringRef Delimiter = StringRef(FirstLine).take_front(DelimiterEnd);4634  if (Delimiter.empty())4635    return Error(DirectiveLoc, "no delimiter in 'comment' directive");4636  do {4637    if (getTok().is(AsmToken::Eof))4638      return Error(DirectiveLoc, "unmatched delimiter in 'comment' directive");4639    Lex();  // eat end of statement4640  } while (4641      !StringRef(parseStringTo(AsmToken::EndOfStatement)).contains(Delimiter));4642  return parseEOL();4643}4644 4645/// parseDirectiveInclude4646///  ::= include <filename>4647///    | include filename4648bool MasmParser::parseDirectiveInclude() {4649  // Allow the strings to have escaped octal character sequence.4650  std::string Filename;4651  SMLoc IncludeLoc = getTok().getLoc();4652 4653  if (parseAngleBracketString(Filename))4654    Filename = parseStringTo(AsmToken::EndOfStatement);4655  if (check(Filename.empty(), "missing filename in 'include' directive") ||4656      check(getTok().isNot(AsmToken::EndOfStatement),4657            "unexpected token in 'include' directive") ||4658      // Attempt to switch the lexer to the included file before consuming the4659      // end of statement to avoid losing it when we switch.4660      check(enterIncludeFile(Filename), IncludeLoc,4661            "Could not find include file '" + Filename + "'"))4662    return true;4663 4664  return false;4665}4666 4667/// parseDirectiveIf4668/// ::= .if{,eq,ge,gt,le,lt,ne} expression4669bool MasmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {4670  TheCondStack.push_back(TheCondState);4671  TheCondState.TheCond = AsmCond::IfCond;4672  if (TheCondState.Ignore) {4673    eatToEndOfStatement();4674  } else {4675    int64_t ExprValue;4676    if (parseAbsoluteExpression(ExprValue) || parseEOL())4677      return true;4678 4679    switch (DirKind) {4680    default:4681      llvm_unreachable("unsupported directive");4682    case DK_IF:4683      break;4684    case DK_IFE:4685      ExprValue = ExprValue == 0;4686      break;4687    }4688 4689    TheCondState.CondMet = ExprValue;4690    TheCondState.Ignore = !TheCondState.CondMet;4691  }4692 4693  return false;4694}4695 4696/// parseDirectiveIfb4697/// ::= .ifb textitem4698bool MasmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {4699  TheCondStack.push_back(TheCondState);4700  TheCondState.TheCond = AsmCond::IfCond;4701 4702  if (TheCondState.Ignore) {4703    eatToEndOfStatement();4704  } else {4705    std::string Str;4706    if (parseTextItem(Str))4707      return TokError("expected text item parameter for 'ifb' directive");4708 4709    if (parseEOL())4710      return true;4711 4712    TheCondState.CondMet = ExpectBlank == Str.empty();4713    TheCondState.Ignore = !TheCondState.CondMet;4714  }4715 4716  return false;4717}4718 4719/// parseDirectiveIfidn4720///   ::= ifidn textitem, textitem4721bool MasmParser::parseDirectiveIfidn(SMLoc DirectiveLoc, bool ExpectEqual,4722                                     bool CaseInsensitive) {4723  std::string String1, String2;4724 4725  if (parseTextItem(String1)) {4726    if (ExpectEqual)4727      return TokError("expected text item parameter for 'ifidn' directive");4728    return TokError("expected text item parameter for 'ifdif' directive");4729  }4730 4731  if (Lexer.isNot(AsmToken::Comma)) {4732    if (ExpectEqual)4733      return TokError(4734          "expected comma after first string for 'ifidn' directive");4735    return TokError("expected comma after first string for 'ifdif' directive");4736  }4737  Lex();4738 4739  if (parseTextItem(String2)) {4740    if (ExpectEqual)4741      return TokError("expected text item parameter for 'ifidn' directive");4742    return TokError("expected text item parameter for 'ifdif' directive");4743  }4744 4745  TheCondStack.push_back(TheCondState);4746  TheCondState.TheCond = AsmCond::IfCond;4747  if (CaseInsensitive)4748    TheCondState.CondMet =4749        ExpectEqual == (StringRef(String1).equals_insensitive(String2));4750  else4751    TheCondState.CondMet = ExpectEqual == (String1 == String2);4752  TheCondState.Ignore = !TheCondState.CondMet;4753 4754  return false;4755}4756 4757/// parseDirectiveIfdef4758/// ::= ifdef symbol4759///   | ifdef variable4760bool MasmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {4761  TheCondStack.push_back(TheCondState);4762  TheCondState.TheCond = AsmCond::IfCond;4763 4764  if (TheCondState.Ignore) {4765    eatToEndOfStatement();4766  } else {4767    bool is_defined = false;4768    MCRegister Reg;4769    SMLoc StartLoc, EndLoc;4770    is_defined =4771        getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();4772    if (!is_defined) {4773      StringRef Name;4774      if (check(parseIdentifier(Name), "expected identifier after 'ifdef'") ||4775          parseEOL())4776        return true;4777 4778      if (BuiltinSymbolMap.contains(Name.lower())) {4779        is_defined = true;4780      } else if (Variables.contains(Name.lower())) {4781        is_defined = true;4782      } else {4783        MCSymbol *Sym = getContext().lookupSymbol(Name.lower());4784        is_defined = (Sym && !Sym->isUndefined());4785      }4786    }4787 4788    TheCondState.CondMet = (is_defined == expect_defined);4789    TheCondState.Ignore = !TheCondState.CondMet;4790  }4791 4792  return false;4793}4794 4795/// parseDirectiveElseIf4796/// ::= elseif expression4797bool MasmParser::parseDirectiveElseIf(SMLoc DirectiveLoc,4798                                      DirectiveKind DirKind) {4799  if (TheCondState.TheCond != AsmCond::IfCond &&4800      TheCondState.TheCond != AsmCond::ElseIfCond)4801    return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an"4802                               " .if or  an .elseif");4803  TheCondState.TheCond = AsmCond::ElseIfCond;4804 4805  bool LastIgnoreState = false;4806  if (!TheCondStack.empty())4807    LastIgnoreState = TheCondStack.back().Ignore;4808  if (LastIgnoreState || TheCondState.CondMet) {4809    TheCondState.Ignore = true;4810    eatToEndOfStatement();4811  } else {4812    int64_t ExprValue;4813    if (parseAbsoluteExpression(ExprValue))4814      return true;4815 4816    if (parseEOL())4817      return true;4818 4819    switch (DirKind) {4820    default:4821      llvm_unreachable("unsupported directive");4822    case DK_ELSEIF:4823      break;4824    case DK_ELSEIFE:4825      ExprValue = ExprValue == 0;4826      break;4827    }4828 4829    TheCondState.CondMet = ExprValue;4830    TheCondState.Ignore = !TheCondState.CondMet;4831  }4832 4833  return false;4834}4835 4836/// parseDirectiveElseIfb4837/// ::= elseifb textitem4838bool MasmParser::parseDirectiveElseIfb(SMLoc DirectiveLoc, bool ExpectBlank) {4839  if (TheCondState.TheCond != AsmCond::IfCond &&4840      TheCondState.TheCond != AsmCond::ElseIfCond)4841    return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"4842                               " if or an elseif");4843  TheCondState.TheCond = AsmCond::ElseIfCond;4844 4845  bool LastIgnoreState = false;4846  if (!TheCondStack.empty())4847    LastIgnoreState = TheCondStack.back().Ignore;4848  if (LastIgnoreState || TheCondState.CondMet) {4849    TheCondState.Ignore = true;4850    eatToEndOfStatement();4851  } else {4852    std::string Str;4853    if (parseTextItem(Str)) {4854      if (ExpectBlank)4855        return TokError("expected text item parameter for 'elseifb' directive");4856      return TokError("expected text item parameter for 'elseifnb' directive");4857    }4858 4859    if (parseEOL())4860      return true;4861 4862    TheCondState.CondMet = ExpectBlank == Str.empty();4863    TheCondState.Ignore = !TheCondState.CondMet;4864  }4865 4866  return false;4867}4868 4869/// parseDirectiveElseIfdef4870/// ::= elseifdef symbol4871///   | elseifdef variable4872bool MasmParser::parseDirectiveElseIfdef(SMLoc DirectiveLoc,4873                                         bool expect_defined) {4874  if (TheCondState.TheCond != AsmCond::IfCond &&4875      TheCondState.TheCond != AsmCond::ElseIfCond)4876    return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"4877                               " if or an elseif");4878  TheCondState.TheCond = AsmCond::ElseIfCond;4879 4880  bool LastIgnoreState = false;4881  if (!TheCondStack.empty())4882    LastIgnoreState = TheCondStack.back().Ignore;4883  if (LastIgnoreState || TheCondState.CondMet) {4884    TheCondState.Ignore = true;4885    eatToEndOfStatement();4886  } else {4887    bool is_defined = false;4888    MCRegister Reg;4889    SMLoc StartLoc, EndLoc;4890    is_defined =4891        getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();4892    if (!is_defined) {4893      StringRef Name;4894      if (check(parseIdentifier(Name),4895                "expected identifier after 'elseifdef'") ||4896          parseEOL())4897        return true;4898 4899      if (BuiltinSymbolMap.contains(Name.lower())) {4900        is_defined = true;4901      } else if (Variables.contains(Name.lower())) {4902        is_defined = true;4903      } else {4904        MCSymbol *Sym = getContext().lookupSymbol(Name);4905        is_defined = (Sym && !Sym->isUndefined());4906      }4907    }4908 4909    TheCondState.CondMet = (is_defined == expect_defined);4910    TheCondState.Ignore = !TheCondState.CondMet;4911  }4912 4913  return false;4914}4915 4916/// parseDirectiveElseIfidn4917/// ::= elseifidn textitem, textitem4918bool MasmParser::parseDirectiveElseIfidn(SMLoc DirectiveLoc, bool ExpectEqual,4919                                         bool CaseInsensitive) {4920  if (TheCondState.TheCond != AsmCond::IfCond &&4921      TheCondState.TheCond != AsmCond::ElseIfCond)4922    return Error(DirectiveLoc, "Encountered an elseif that doesn't follow an"4923                               " if or an elseif");4924  TheCondState.TheCond = AsmCond::ElseIfCond;4925 4926  bool LastIgnoreState = false;4927  if (!TheCondStack.empty())4928    LastIgnoreState = TheCondStack.back().Ignore;4929  if (LastIgnoreState || TheCondState.CondMet) {4930    TheCondState.Ignore = true;4931    eatToEndOfStatement();4932  } else {4933    std::string String1, String2;4934 4935    if (parseTextItem(String1)) {4936      if (ExpectEqual)4937        return TokError(4938            "expected text item parameter for 'elseifidn' directive");4939      return TokError("expected text item parameter for 'elseifdif' directive");4940    }4941 4942    if (Lexer.isNot(AsmToken::Comma)) {4943      if (ExpectEqual)4944        return TokError(4945            "expected comma after first string for 'elseifidn' directive");4946      return TokError(4947          "expected comma after first string for 'elseifdif' directive");4948    }4949    Lex();4950 4951    if (parseTextItem(String2)) {4952      if (ExpectEqual)4953        return TokError(4954            "expected text item parameter for 'elseifidn' directive");4955      return TokError("expected text item parameter for 'elseifdif' directive");4956    }4957 4958    if (CaseInsensitive)4959      TheCondState.CondMet =4960          ExpectEqual == (StringRef(String1).equals_insensitive(String2));4961    else4962      TheCondState.CondMet = ExpectEqual == (String1 == String2);4963    TheCondState.Ignore = !TheCondState.CondMet;4964  }4965 4966  return false;4967}4968 4969/// parseDirectiveElse4970/// ::= else4971bool MasmParser::parseDirectiveElse(SMLoc DirectiveLoc) {4972  if (parseEOL())4973    return true;4974 4975  if (TheCondState.TheCond != AsmCond::IfCond &&4976      TheCondState.TheCond != AsmCond::ElseIfCond)4977    return Error(DirectiveLoc, "Encountered an else that doesn't follow an if"4978                               " or an elseif");4979  TheCondState.TheCond = AsmCond::ElseCond;4980  bool LastIgnoreState = false;4981  if (!TheCondStack.empty())4982    LastIgnoreState = TheCondStack.back().Ignore;4983  if (LastIgnoreState || TheCondState.CondMet)4984    TheCondState.Ignore = true;4985  else4986    TheCondState.Ignore = false;4987 4988  return false;4989}4990 4991/// parseDirectiveEnd4992/// ::= end4993bool MasmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {4994  if (parseEOL())4995    return true;4996 4997  while (Lexer.isNot(AsmToken::Eof))4998    Lexer.Lex();4999 5000  return false;5001}5002 5003/// parseDirectiveError5004///   ::= .err [message]5005bool MasmParser::parseDirectiveError(SMLoc DirectiveLoc) {5006  if (!TheCondStack.empty()) {5007    if (TheCondStack.back().Ignore) {5008      eatToEndOfStatement();5009      return false;5010    }5011  }5012 5013  std::string Message = ".err directive invoked in source file";5014  if (Lexer.isNot(AsmToken::EndOfStatement))5015    Message = parseStringTo(AsmToken::EndOfStatement);5016  Lex();5017 5018  return Error(DirectiveLoc, Message);5019}5020 5021/// parseDirectiveErrorIfb5022///   ::= .errb textitem[, message]5023bool MasmParser::parseDirectiveErrorIfb(SMLoc DirectiveLoc, bool ExpectBlank) {5024  if (!TheCondStack.empty()) {5025    if (TheCondStack.back().Ignore) {5026      eatToEndOfStatement();5027      return false;5028    }5029  }5030 5031  std::string Text;5032  if (parseTextItem(Text))5033    return Error(getTok().getLoc(), "missing text item in '.errb' directive");5034 5035  std::string Message = ".errb directive invoked in source file";5036  if (Lexer.isNot(AsmToken::EndOfStatement)) {5037    if (parseToken(AsmToken::Comma))5038      return addErrorSuffix(" in '.errb' directive");5039    Message = parseStringTo(AsmToken::EndOfStatement);5040  }5041  Lex();5042 5043  if (Text.empty() == ExpectBlank)5044    return Error(DirectiveLoc, Message);5045  return false;5046}5047 5048/// parseDirectiveErrorIfdef5049///   ::= .errdef name[, message]5050bool MasmParser::parseDirectiveErrorIfdef(SMLoc DirectiveLoc,5051                                          bool ExpectDefined) {5052  if (!TheCondStack.empty()) {5053    if (TheCondStack.back().Ignore) {5054      eatToEndOfStatement();5055      return false;5056    }5057  }5058 5059  bool IsDefined = false;5060  MCRegister Reg;5061  SMLoc StartLoc, EndLoc;5062  IsDefined =5063      getTargetParser().tryParseRegister(Reg, StartLoc, EndLoc).isSuccess();5064  if (!IsDefined) {5065    StringRef Name;5066    if (check(parseIdentifier(Name), "expected identifier after '.errdef'"))5067      return true;5068 5069    if (BuiltinSymbolMap.contains(Name.lower())) {5070      IsDefined = true;5071    } else if (Variables.contains(Name.lower())) {5072      IsDefined = true;5073    } else {5074      MCSymbol *Sym = getContext().lookupSymbol(Name);5075      IsDefined = (Sym && !Sym->isUndefined());5076    }5077  }5078 5079  std::string Message = ".errdef directive invoked in source file";5080  if (Lexer.isNot(AsmToken::EndOfStatement)) {5081    if (parseToken(AsmToken::Comma))5082      return addErrorSuffix(" in '.errdef' directive");5083    Message = parseStringTo(AsmToken::EndOfStatement);5084  }5085  Lex();5086 5087  if (IsDefined == ExpectDefined)5088    return Error(DirectiveLoc, Message);5089  return false;5090}5091 5092/// parseDirectiveErrorIfidn5093///   ::= .erridn textitem, textitem[, message]5094bool MasmParser::parseDirectiveErrorIfidn(SMLoc DirectiveLoc, bool ExpectEqual,5095                                          bool CaseInsensitive) {5096  if (!TheCondStack.empty()) {5097    if (TheCondStack.back().Ignore) {5098      eatToEndOfStatement();5099      return false;5100    }5101  }5102 5103  std::string String1, String2;5104 5105  if (parseTextItem(String1)) {5106    if (ExpectEqual)5107      return TokError("expected string parameter for '.erridn' directive");5108    return TokError("expected string parameter for '.errdif' directive");5109  }5110 5111  if (Lexer.isNot(AsmToken::Comma)) {5112    if (ExpectEqual)5113      return TokError(5114          "expected comma after first string for '.erridn' directive");5115    return TokError(5116        "expected comma after first string for '.errdif' directive");5117  }5118  Lex();5119 5120  if (parseTextItem(String2)) {5121    if (ExpectEqual)5122      return TokError("expected string parameter for '.erridn' directive");5123    return TokError("expected string parameter for '.errdif' directive");5124  }5125 5126  std::string Message;5127  if (ExpectEqual)5128    Message = ".erridn directive invoked in source file";5129  else5130    Message = ".errdif directive invoked in source file";5131  if (Lexer.isNot(AsmToken::EndOfStatement)) {5132    if (parseToken(AsmToken::Comma))5133      return addErrorSuffix(" in '.erridn' directive");5134    Message = parseStringTo(AsmToken::EndOfStatement);5135  }5136  Lex();5137 5138  if (CaseInsensitive)5139    TheCondState.CondMet =5140        ExpectEqual == (StringRef(String1).equals_insensitive(String2));5141  else5142    TheCondState.CondMet = ExpectEqual == (String1 == String2);5143  TheCondState.Ignore = !TheCondState.CondMet;5144 5145  if ((CaseInsensitive &&5146       ExpectEqual == StringRef(String1).equals_insensitive(String2)) ||5147      (ExpectEqual == (String1 == String2)))5148    return Error(DirectiveLoc, Message);5149  return false;5150}5151 5152/// parseDirectiveErrorIfe5153///   ::= .erre expression[, message]5154bool MasmParser::parseDirectiveErrorIfe(SMLoc DirectiveLoc, bool ExpectZero) {5155  if (!TheCondStack.empty()) {5156    if (TheCondStack.back().Ignore) {5157      eatToEndOfStatement();5158      return false;5159    }5160  }5161 5162  int64_t ExprValue;5163  if (parseAbsoluteExpression(ExprValue))5164    return addErrorSuffix(" in '.erre' directive");5165 5166  std::string Message = ".erre directive invoked in source file";5167  if (Lexer.isNot(AsmToken::EndOfStatement)) {5168    if (parseToken(AsmToken::Comma))5169      return addErrorSuffix(" in '.erre' directive");5170    Message = parseStringTo(AsmToken::EndOfStatement);5171  }5172  Lex();5173 5174  if ((ExprValue == 0) == ExpectZero)5175    return Error(DirectiveLoc, Message);5176  return false;5177}5178 5179/// parseDirectiveEndIf5180/// ::= .endif5181bool MasmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {5182  if (parseEOL())5183    return true;5184 5185  if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())5186    return Error(DirectiveLoc, "Encountered a .endif that doesn't follow "5187                               "an .if or .else");5188  if (!TheCondStack.empty()) {5189    TheCondState = TheCondStack.back();5190    TheCondStack.pop_back();5191  }5192 5193  return false;5194}5195 5196void MasmParser::initializeDirectiveKindMap() {5197  DirectiveKindMap["="] = DK_ASSIGN;5198  DirectiveKindMap["equ"] = DK_EQU;5199  DirectiveKindMap["textequ"] = DK_TEXTEQU;5200  // DirectiveKindMap[".ascii"] = DK_ASCII;5201  // DirectiveKindMap[".asciz"] = DK_ASCIZ;5202  // DirectiveKindMap[".string"] = DK_STRING;5203  DirectiveKindMap["byte"] = DK_BYTE;5204  DirectiveKindMap["sbyte"] = DK_SBYTE;5205  DirectiveKindMap["word"] = DK_WORD;5206  DirectiveKindMap["sword"] = DK_SWORD;5207  DirectiveKindMap["dword"] = DK_DWORD;5208  DirectiveKindMap["sdword"] = DK_SDWORD;5209  DirectiveKindMap["fword"] = DK_FWORD;5210  DirectiveKindMap["qword"] = DK_QWORD;5211  DirectiveKindMap["sqword"] = DK_SQWORD;5212  DirectiveKindMap["real4"] = DK_REAL4;5213  DirectiveKindMap["real8"] = DK_REAL8;5214  DirectiveKindMap["real10"] = DK_REAL10;5215  DirectiveKindMap["align"] = DK_ALIGN;5216  DirectiveKindMap["even"] = DK_EVEN;5217  DirectiveKindMap["org"] = DK_ORG;5218  DirectiveKindMap["extern"] = DK_EXTERN;5219  DirectiveKindMap["extrn"] = DK_EXTERN;5220  DirectiveKindMap["public"] = DK_PUBLIC;5221  // DirectiveKindMap[".comm"] = DK_COMM;5222  DirectiveKindMap["comment"] = DK_COMMENT;5223  DirectiveKindMap["include"] = DK_INCLUDE;5224  DirectiveKindMap["repeat"] = DK_REPEAT;5225  DirectiveKindMap["rept"] = DK_REPEAT;5226  DirectiveKindMap["while"] = DK_WHILE;5227  DirectiveKindMap["for"] = DK_FOR;5228  DirectiveKindMap["irp"] = DK_FOR;5229  DirectiveKindMap["forc"] = DK_FORC;5230  DirectiveKindMap["irpc"] = DK_FORC;5231  DirectiveKindMap["if"] = DK_IF;5232  DirectiveKindMap["ife"] = DK_IFE;5233  DirectiveKindMap["ifb"] = DK_IFB;5234  DirectiveKindMap["ifnb"] = DK_IFNB;5235  DirectiveKindMap["ifdef"] = DK_IFDEF;5236  DirectiveKindMap["ifndef"] = DK_IFNDEF;5237  DirectiveKindMap["ifdif"] = DK_IFDIF;5238  DirectiveKindMap["ifdifi"] = DK_IFDIFI;5239  DirectiveKindMap["ifidn"] = DK_IFIDN;5240  DirectiveKindMap["ifidni"] = DK_IFIDNI;5241  DirectiveKindMap["elseif"] = DK_ELSEIF;5242  DirectiveKindMap["elseifdef"] = DK_ELSEIFDEF;5243  DirectiveKindMap["elseifndef"] = DK_ELSEIFNDEF;5244  DirectiveKindMap["elseifdif"] = DK_ELSEIFDIF;5245  DirectiveKindMap["elseifidn"] = DK_ELSEIFIDN;5246  DirectiveKindMap["else"] = DK_ELSE;5247  DirectiveKindMap["end"] = DK_END;5248  DirectiveKindMap["endif"] = DK_ENDIF;5249  // DirectiveKindMap[".file"] = DK_FILE;5250  // DirectiveKindMap[".line"] = DK_LINE;5251  // DirectiveKindMap[".loc"] = DK_LOC;5252  // DirectiveKindMap[".stabs"] = DK_STABS;5253  // DirectiveKindMap[".cv_file"] = DK_CV_FILE;5254  // DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;5255  // DirectiveKindMap[".cv_loc"] = DK_CV_LOC;5256  // DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;5257  // DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;5258  // DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;5259  // DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;5260  // DirectiveKindMap[".cv_string"] = DK_CV_STRING;5261  // DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;5262  // DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;5263  // DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;5264  // DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;5265  // DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;5266  // DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;5267  // DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;5268  // DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;5269  // DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;5270  // DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;5271  // DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;5272  // DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;5273  // DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;5274  // DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;5275  // DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;5276  // DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;5277  // DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;5278  // DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;5279  // DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;5280  // DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;5281  // DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;5282  // DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;5283  // DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;5284  // DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;5285  // DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;5286  // DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;5287  // DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET;5288  DirectiveKindMap["macro"] = DK_MACRO;5289  DirectiveKindMap["exitm"] = DK_EXITM;5290  DirectiveKindMap["endm"] = DK_ENDM;5291  DirectiveKindMap["purge"] = DK_PURGE;5292  DirectiveKindMap[".err"] = DK_ERR;5293  DirectiveKindMap[".errb"] = DK_ERRB;5294  DirectiveKindMap[".errnb"] = DK_ERRNB;5295  DirectiveKindMap[".errdef"] = DK_ERRDEF;5296  DirectiveKindMap[".errndef"] = DK_ERRNDEF;5297  DirectiveKindMap[".errdif"] = DK_ERRDIF;5298  DirectiveKindMap[".errdifi"] = DK_ERRDIFI;5299  DirectiveKindMap[".erridn"] = DK_ERRIDN;5300  DirectiveKindMap[".erridni"] = DK_ERRIDNI;5301  DirectiveKindMap[".erre"] = DK_ERRE;5302  DirectiveKindMap[".errnz"] = DK_ERRNZ;5303  DirectiveKindMap[".pushframe"] = DK_PUSHFRAME;5304  DirectiveKindMap[".pushreg"] = DK_PUSHREG;5305  DirectiveKindMap[".savereg"] = DK_SAVEREG;5306  DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128;5307  DirectiveKindMap[".setframe"] = DK_SETFRAME;5308  DirectiveKindMap[".radix"] = DK_RADIX;5309  DirectiveKindMap["db"] = DK_DB;5310  DirectiveKindMap["dd"] = DK_DD;5311  DirectiveKindMap["df"] = DK_DF;5312  DirectiveKindMap["dq"] = DK_DQ;5313  DirectiveKindMap["dw"] = DK_DW;5314  DirectiveKindMap["echo"] = DK_ECHO;5315  DirectiveKindMap["struc"] = DK_STRUCT;5316  DirectiveKindMap["struct"] = DK_STRUCT;5317  DirectiveKindMap["union"] = DK_UNION;5318  DirectiveKindMap["ends"] = DK_ENDS;5319}5320 5321bool MasmParser::isMacroLikeDirective() {5322  if (getLexer().is(AsmToken::Identifier)) {5323    bool IsMacroLike = StringSwitch<bool>(getTok().getIdentifier())5324                           .CasesLower({"repeat", "rept"}, true)5325                           .CaseLower("while", true)5326                           .CasesLower({"for", "irp"}, true)5327                           .CasesLower({"forc", "irpc"}, true)5328                           .Default(false);5329    if (IsMacroLike)5330      return true;5331  }5332  if (peekTok().is(AsmToken::Identifier) &&5333      peekTok().getIdentifier().equals_insensitive("macro"))5334    return true;5335 5336  return false;5337}5338 5339MCAsmMacro *MasmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {5340  AsmToken EndToken, StartToken = getTok();5341 5342  unsigned NestLevel = 0;5343  while (true) {5344    // Check whether we have reached the end of the file.5345    if (getLexer().is(AsmToken::Eof)) {5346      printError(DirectiveLoc, "no matching 'endm' in definition");5347      return nullptr;5348    }5349 5350    if (isMacroLikeDirective())5351      ++NestLevel;5352 5353    // Otherwise, check whether we have reached the endm.5354    if (Lexer.is(AsmToken::Identifier) &&5355        getTok().getIdentifier().equals_insensitive("endm")) {5356      if (NestLevel == 0) {5357        EndToken = getTok();5358        Lex();5359        if (Lexer.isNot(AsmToken::EndOfStatement)) {5360          printError(getTok().getLoc(), "unexpected token in 'endm' directive");5361          return nullptr;5362        }5363        break;5364      }5365      --NestLevel;5366    }5367 5368    // Otherwise, scan till the end of the statement.5369    eatToEndOfStatement();5370  }5371 5372  const char *BodyStart = StartToken.getLoc().getPointer();5373  const char *BodyEnd = EndToken.getLoc().getPointer();5374  StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);5375 5376  // We Are Anonymous.5377  MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters());5378  return &MacroLikeBodies.back();5379}5380 5381bool MasmParser::expandStatement(SMLoc Loc) {5382  std::string Body = parseStringTo(AsmToken::EndOfStatement);5383  SMLoc EndLoc = getTok().getLoc();5384 5385  MCAsmMacroParameters Parameters;5386  MCAsmMacroArguments Arguments;5387 5388  StringMap<std::string> BuiltinValues;5389  for (const auto &S : BuiltinSymbolMap) {5390    const BuiltinSymbol &Sym = S.getValue();5391    if (std::optional<std::string> Text = evaluateBuiltinTextMacro(Sym, Loc)) {5392      BuiltinValues[S.getKey().lower()] = std::move(*Text);5393    }5394  }5395  for (const auto &B : BuiltinValues) {5396    MCAsmMacroParameter P;5397    MCAsmMacroArgument A;5398    P.Name = B.getKey();5399    P.Required = true;5400    A.push_back(AsmToken(AsmToken::String, B.getValue()));5401 5402    Parameters.push_back(std::move(P));5403    Arguments.push_back(std::move(A));5404  }5405 5406  for (const auto &V : Variables) {5407    const Variable &Var = V.getValue();5408    if (Var.IsText) {5409      MCAsmMacroParameter P;5410      MCAsmMacroArgument A;5411      P.Name = Var.Name;5412      P.Required = true;5413      A.push_back(AsmToken(AsmToken::String, Var.TextValue));5414 5415      Parameters.push_back(std::move(P));5416      Arguments.push_back(std::move(A));5417    }5418  }5419  MacroLikeBodies.emplace_back(StringRef(), Body, Parameters);5420  MCAsmMacro M = MacroLikeBodies.back();5421 5422  // Expand the statement in a new buffer.5423  SmallString<80> Buf;5424  raw_svector_ostream OS(Buf);5425  if (expandMacro(OS, M.Body, M.Parameters, Arguments, M.Locals, EndLoc))5426    return true;5427  std::unique_ptr<MemoryBuffer> Expansion =5428      MemoryBuffer::getMemBufferCopy(OS.str(), "<expansion>");5429 5430  // Jump to the expanded statement and prime the lexer.5431  CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Expansion), EndLoc);5432  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());5433  EndStatementAtEOFStack.push_back(false);5434  Lex();5435  return false;5436}5437 5438void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,5439                                          raw_svector_ostream &OS) {5440  instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/getTok().getLoc(), OS);5441}5442void MasmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,5443                                          SMLoc ExitLoc,5444                                          raw_svector_ostream &OS) {5445  OS << "endm\n";5446 5447  std::unique_ptr<MemoryBuffer> Instantiation =5448      MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");5449 5450  // Create the macro instantiation object and add to the current macro5451  // instantiation stack.5452  MacroInstantiation *MI = new MacroInstantiation{DirectiveLoc, CurBuffer,5453                                                  ExitLoc, TheCondStack.size()};5454  ActiveMacros.push_back(MI);5455 5456  // Jump to the macro instantiation and prime the lexer.5457  CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());5458  Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());5459  EndStatementAtEOFStack.push_back(true);5460  Lex();5461}5462 5463/// parseDirectiveRepeat5464///   ::= ("repeat" | "rept") count5465///       body5466///     endm5467bool MasmParser::parseDirectiveRepeat(SMLoc DirectiveLoc, StringRef Dir) {5468  const MCExpr *CountExpr;5469  SMLoc CountLoc = getTok().getLoc();5470  if (parseExpression(CountExpr))5471    return true;5472 5473  int64_t Count;5474  if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) {5475    return Error(CountLoc, "unexpected token in '" + Dir + "' directive");5476  }5477 5478  if (check(Count < 0, CountLoc, "Count is negative") || parseEOL())5479    return true;5480 5481  // Lex the repeat definition.5482  MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5483  if (!M)5484    return true;5485 5486  // Macro instantiation is lexical, unfortunately. We construct a new buffer5487  // to hold the macro body with substitutions.5488  SmallString<256> Buf;5489  raw_svector_ostream OS(Buf);5490  while (Count--) {5491    if (expandMacro(OS, M->Body, {}, {}, M->Locals, getTok().getLoc()))5492      return true;5493  }5494  instantiateMacroLikeBody(M, DirectiveLoc, OS);5495 5496  return false;5497}5498 5499/// parseDirectiveWhile5500/// ::= "while" expression5501///       body5502///     endm5503bool MasmParser::parseDirectiveWhile(SMLoc DirectiveLoc) {5504  const MCExpr *CondExpr;5505  SMLoc CondLoc = getTok().getLoc();5506  if (parseExpression(CondExpr))5507    return true;5508 5509  // Lex the repeat definition.5510  MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5511  if (!M)5512    return true;5513 5514  // Macro instantiation is lexical, unfortunately. We construct a new buffer5515  // to hold the macro body with substitutions.5516  SmallString<256> Buf;5517  raw_svector_ostream OS(Buf);5518  int64_t Condition;5519  if (!CondExpr->evaluateAsAbsolute(Condition, getStreamer().getAssemblerPtr()))5520    return Error(CondLoc, "expected absolute expression in 'while' directive");5521  if (Condition) {5522    // Instantiate the macro, then resume at this directive to recheck the5523    // condition.5524    if (expandMacro(OS, M->Body, {}, {}, M->Locals, getTok().getLoc()))5525      return true;5526    instantiateMacroLikeBody(M, DirectiveLoc, /*ExitLoc=*/DirectiveLoc, OS);5527  }5528 5529  return false;5530}5531 5532/// parseDirectiveFor5533/// ::= ("for" | "irp") symbol [":" qualifier], <values>5534///       body5535///     endm5536bool MasmParser::parseDirectiveFor(SMLoc DirectiveLoc, StringRef Dir) {5537  MCAsmMacroParameter Parameter;5538  MCAsmMacroArguments A;5539  if (check(parseIdentifier(Parameter.Name),5540            "expected identifier in '" + Dir + "' directive"))5541    return true;5542 5543  // Parse optional qualifier (default value, or "req")5544  if (parseOptionalToken(AsmToken::Colon)) {5545    if (parseOptionalToken(AsmToken::Equal)) {5546      // Default value5547      SMLoc ParamLoc;5548 5549      ParamLoc = Lexer.getLoc();5550      if (parseMacroArgument(nullptr, Parameter.Value))5551        return true;5552    } else {5553      SMLoc QualLoc;5554      StringRef Qualifier;5555 5556      QualLoc = Lexer.getLoc();5557      if (parseIdentifier(Qualifier))5558        return Error(QualLoc, "missing parameter qualifier for "5559                              "'" +5560                                  Parameter.Name + "' in '" + Dir +5561                                  "' directive");5562 5563      if (Qualifier.equals_insensitive("req"))5564        Parameter.Required = true;5565      else5566        return Error(QualLoc,5567                     Qualifier + " is not a valid parameter qualifier for '" +5568                         Parameter.Name + "' in '" + Dir + "' directive");5569    }5570  }5571 5572  if (parseToken(AsmToken::Comma,5573                 "expected comma in '" + Dir + "' directive") ||5574      parseToken(AsmToken::Less,5575                 "values in '" + Dir +5576                     "' directive must be enclosed in angle brackets"))5577    return true;5578 5579  while (true) {5580    A.emplace_back();5581    if (parseMacroArgument(&Parameter, A.back(), /*EndTok=*/AsmToken::Greater))5582      return addErrorSuffix(" in arguments for '" + Dir + "' directive");5583 5584    // If we see a comma, continue, and allow line continuation.5585    if (!parseOptionalToken(AsmToken::Comma))5586      break;5587    parseOptionalToken(AsmToken::EndOfStatement);5588  }5589 5590  if (parseToken(AsmToken::Greater,5591                 "values in '" + Dir +5592                     "' directive must be enclosed in angle brackets") ||5593      parseEOL())5594    return true;5595 5596  // Lex the for definition.5597  MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5598  if (!M)5599    return true;5600 5601  // Macro instantiation is lexical, unfortunately. We construct a new buffer5602  // to hold the macro body with substitutions.5603  SmallString<256> Buf;5604  raw_svector_ostream OS(Buf);5605 5606  for (const MCAsmMacroArgument &Arg : A) {5607    if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))5608      return true;5609  }5610 5611  instantiateMacroLikeBody(M, DirectiveLoc, OS);5612 5613  return false;5614}5615 5616/// parseDirectiveForc5617/// ::= ("forc" | "irpc") symbol, <string>5618///       body5619///     endm5620bool MasmParser::parseDirectiveForc(SMLoc DirectiveLoc, StringRef Directive) {5621  MCAsmMacroParameter Parameter;5622 5623  std::string Argument;5624  if (check(parseIdentifier(Parameter.Name),5625            "expected identifier in '" + Directive + "' directive") ||5626      parseToken(AsmToken::Comma,5627                 "expected comma in '" + Directive + "' directive"))5628    return true;5629  if (parseAngleBracketString(Argument)) {5630    // Match ml64.exe; treat all characters to end of statement as a string,5631    // ignoring comment markers, then discard anything following a space (using5632    // the C locale).5633    Argument = parseStringTo(AsmToken::EndOfStatement);5634    if (getTok().is(AsmToken::EndOfStatement))5635      Argument += getTok().getString();5636    size_t End = 0;5637    for (; End < Argument.size(); ++End) {5638      if (isSpace(Argument[End]))5639        break;5640    }5641    Argument.resize(End);5642  }5643  if (parseEOL())5644    return true;5645 5646  // Lex the irpc definition.5647  MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);5648  if (!M)5649    return true;5650 5651  // Macro instantiation is lexical, unfortunately. We construct a new buffer5652  // to hold the macro body with substitutions.5653  SmallString<256> Buf;5654  raw_svector_ostream OS(Buf);5655 5656  StringRef Values(Argument);5657  for (std::size_t I = 0, End = Values.size(); I != End; ++I) {5658    MCAsmMacroArgument Arg;5659    Arg.emplace_back(AsmToken::Identifier, Values.substr(I, 1));5660 5661    if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))5662      return true;5663  }5664 5665  instantiateMacroLikeBody(M, DirectiveLoc, OS);5666 5667  return false;5668}5669 5670bool MasmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,5671                                      size_t Len) {5672  const MCExpr *Value;5673  SMLoc ExprLoc = getLexer().getLoc();5674  if (parseExpression(Value))5675    return true;5676  const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);5677  if (!MCE)5678    return Error(ExprLoc, "unexpected expression in _emit");5679  uint64_t IntValue = MCE->getValue();5680  if (!isUInt<8>(IntValue) && !isInt<8>(IntValue))5681    return Error(ExprLoc, "literal value out of range for directive");5682 5683  Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);5684  return false;5685}5686 5687bool MasmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {5688  const MCExpr *Value;5689  SMLoc ExprLoc = getLexer().getLoc();5690  if (parseExpression(Value))5691    return true;5692  const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);5693  if (!MCE)5694    return Error(ExprLoc, "unexpected expression in align");5695  uint64_t IntValue = MCE->getValue();5696  if (!isPowerOf2_64(IntValue))5697    return Error(ExprLoc, "literal value not a power of two greater then zero");5698 5699  Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue));5700  return false;5701}5702 5703bool MasmParser::parseDirectiveRadix(SMLoc DirectiveLoc) {5704  const SMLoc Loc = getLexer().getLoc();5705  std::string RadixStringRaw = parseStringTo(AsmToken::EndOfStatement);5706  StringRef RadixString = StringRef(RadixStringRaw).trim();5707  unsigned Radix;5708  if (RadixString.getAsInteger(10, Radix)) {5709    return Error(Loc,5710                 "radix must be a decimal number in the range 2 to 16; was " +5711                     RadixString);5712  }5713  if (Radix < 2 || Radix > 16)5714    return Error(Loc, "radix must be in the range 2 to 16; was " +5715                          std::to_string(Radix));5716  getLexer().setMasmDefaultRadix(Radix);5717  return false;5718}5719 5720/// parseDirectiveEcho5721///   ::= "echo" message5722bool MasmParser::parseDirectiveEcho(SMLoc DirectiveLoc) {5723  std::string Message = parseStringTo(AsmToken::EndOfStatement);5724  llvm::outs() << Message;5725  if (!StringRef(Message).ends_with("\n"))5726    llvm::outs() << '\n';5727  return false;5728}5729 5730// We are comparing pointers, but the pointers are relative to a single string.5731// Thus, this should always be deterministic.5732static int rewritesSort(const AsmRewrite *AsmRewriteA,5733                        const AsmRewrite *AsmRewriteB) {5734  if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())5735    return -1;5736  if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())5737    return 1;5738 5739  // It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output5740  // rewrite to the same location.  Make sure the SizeDirective rewrite is5741  // performed first, then the Imm/ImmPrefix and finally the Input/Output.  This5742  // ensures the sort algorithm is stable.5743  if (AsmRewritePrecedence[AsmRewriteA->Kind] >5744      AsmRewritePrecedence[AsmRewriteB->Kind])5745    return -1;5746 5747  if (AsmRewritePrecedence[AsmRewriteA->Kind] <5748      AsmRewritePrecedence[AsmRewriteB->Kind])5749    return 1;5750  llvm_unreachable("Unstable rewrite sort.");5751}5752 5753bool MasmParser::defineMacro(StringRef Name, StringRef Value) {5754  Variable &Var = Variables[Name.lower()];5755  if (Var.Name.empty()) {5756    Var.Name = Name;5757  } else if (Var.Redefinable == Variable::NOT_REDEFINABLE) {5758    return Error(SMLoc(), "invalid variable redefinition");5759  } else if (Var.Redefinable == Variable::WARN_ON_REDEFINITION &&5760             Warning(SMLoc(), "redefining '" + Name +5761                                  "', already defined on the command line")) {5762    return true;5763  }5764  Var.Redefinable = Variable::WARN_ON_REDEFINITION;5765  Var.IsText = true;5766  Var.TextValue = Value.str();5767  return false;5768}5769 5770bool MasmParser::lookUpField(StringRef Name, AsmFieldInfo &Info) const {5771  const std::pair<StringRef, StringRef> BaseMember = Name.split('.');5772  const StringRef Base = BaseMember.first, Member = BaseMember.second;5773  return lookUpField(Base, Member, Info);5774}5775 5776bool MasmParser::lookUpField(StringRef Base, StringRef Member,5777                             AsmFieldInfo &Info) const {5778  if (Base.empty())5779    return true;5780 5781  AsmFieldInfo BaseInfo;5782  if (Base.contains('.') && !lookUpField(Base, BaseInfo))5783    Base = BaseInfo.Type.Name;5784 5785  auto StructIt = Structs.find(Base.lower());5786  auto TypeIt = KnownType.find(Base.lower());5787  if (TypeIt != KnownType.end()) {5788    StructIt = Structs.find(TypeIt->second.Name.lower());5789  }5790  if (StructIt != Structs.end())5791    return lookUpField(StructIt->second, Member, Info);5792 5793  return true;5794}5795 5796bool MasmParser::lookUpField(const StructInfo &Structure, StringRef Member,5797                             AsmFieldInfo &Info) const {5798  if (Member.empty()) {5799    Info.Type.Name = Structure.Name;5800    Info.Type.Size = Structure.Size;5801    Info.Type.ElementSize = Structure.Size;5802    Info.Type.Length = 1;5803    return false;5804  }5805 5806  std::pair<StringRef, StringRef> Split = Member.split('.');5807  const StringRef FieldName = Split.first, FieldMember = Split.second;5808 5809  auto StructIt = Structs.find(FieldName.lower());5810  if (StructIt != Structs.end())5811    return lookUpField(StructIt->second, FieldMember, Info);5812 5813  auto FieldIt = Structure.FieldsByName.find(FieldName.lower());5814  if (FieldIt == Structure.FieldsByName.end())5815    return true;5816 5817  const FieldInfo &Field = Structure.Fields[FieldIt->second];5818  if (FieldMember.empty()) {5819    Info.Offset += Field.Offset;5820    Info.Type.Size = Field.SizeOf;5821    Info.Type.ElementSize = Field.Type;5822    Info.Type.Length = Field.LengthOf;5823    if (Field.Contents.FT == FT_STRUCT)5824      Info.Type.Name = Field.Contents.StructInfo.Structure.Name;5825    else5826      Info.Type.Name = "";5827    return false;5828  }5829 5830  if (Field.Contents.FT != FT_STRUCT)5831    return true;5832  const StructFieldInfo &StructInfo = Field.Contents.StructInfo;5833 5834  if (lookUpField(StructInfo.Structure, FieldMember, Info))5835    return true;5836 5837  Info.Offset += Field.Offset;5838  return false;5839}5840 5841bool MasmParser::lookUpType(StringRef Name, AsmTypeInfo &Info) const {5842  unsigned Size = StringSwitch<unsigned>(Name)5843                      .CasesLower({"byte", "db", "sbyte"}, 1)5844                      .CasesLower({"word", "dw", "sword"}, 2)5845                      .CasesLower({"dword", "dd", "sdword"}, 4)5846                      .CasesLower({"fword", "df"}, 6)5847                      .CasesLower({"qword", "dq", "sqword"}, 8)5848                      .CaseLower("real4", 4)5849                      .CaseLower("real8", 8)5850                      .CaseLower("real10", 10)5851                      .Default(0);5852  if (Size) {5853    Info.Name = Name;5854    Info.ElementSize = Size;5855    Info.Length = 1;5856    Info.Size = Size;5857    return false;5858  }5859 5860  auto StructIt = Structs.find(Name.lower());5861  if (StructIt != Structs.end()) {5862    const StructInfo &Structure = StructIt->second;5863    Info.Name = Name;5864    Info.ElementSize = Structure.Size;5865    Info.Length = 1;5866    Info.Size = Structure.Size;5867    return false;5868  }5869 5870  return true;5871}5872 5873bool MasmParser::parseMSInlineAsm(5874    std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs,5875    SmallVectorImpl<std::pair<void *, bool>> &OpDecls,5876    SmallVectorImpl<std::string> &Constraints,5877    SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,5878    MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {5879  SmallVector<void *, 4> InputDecls;5880  SmallVector<void *, 4> OutputDecls;5881  SmallVector<bool, 4> InputDeclsAddressOf;5882  SmallVector<bool, 4> OutputDeclsAddressOf;5883  SmallVector<std::string, 4> InputConstraints;5884  SmallVector<std::string, 4> OutputConstraints;5885  SmallVector<MCRegister, 4> ClobberRegs;5886 5887  SmallVector<AsmRewrite, 4> AsmStrRewrites;5888 5889  // Prime the lexer.5890  Lex();5891 5892  // While we have input, parse each statement.5893  unsigned InputIdx = 0;5894  unsigned OutputIdx = 0;5895  while (getLexer().isNot(AsmToken::Eof)) {5896    // Parse curly braces marking block start/end.5897    if (parseCurlyBlockScope(AsmStrRewrites))5898      continue;5899 5900    ParseStatementInfo Info(&AsmStrRewrites);5901    bool StatementErr = parseStatement(Info, &SI);5902 5903    if (StatementErr || Info.ParseError) {5904      // Emit pending errors if any exist.5905      printPendingErrors();5906      return true;5907    }5908 5909    // No pending error should exist here.5910    assert(!hasPendingError() && "unexpected error from parseStatement");5911 5912    if (Info.Opcode == ~0U)5913      continue;5914 5915    const MCInstrDesc &Desc = MII->get(Info.Opcode);5916 5917    // Build the list of clobbers, outputs and inputs.5918    for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {5919      MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];5920 5921      // Register operand.5922      if (Operand.isReg() && !Operand.needAddressOf() &&5923          !getTargetParser().omitRegisterFromClobberLists(Operand.getReg())) {5924        unsigned NumDefs = Desc.getNumDefs();5925        // Clobber.5926        if (NumDefs && Operand.getMCOperandNum() < NumDefs)5927          ClobberRegs.push_back(Operand.getReg());5928        continue;5929      }5930 5931      // Expr/Input or Output.5932      StringRef SymName = Operand.getSymName();5933      if (SymName.empty())5934        continue;5935 5936      void *OpDecl = Operand.getOpDecl();5937      if (!OpDecl)5938        continue;5939 5940      StringRef Constraint = Operand.getConstraint();5941      if (Operand.isImm()) {5942        // Offset as immediate.5943        if (Operand.isOffsetOfLocal())5944          Constraint = "r";5945        else5946          Constraint = "i";5947      }5948 5949      bool isOutput = (i == 1) && Desc.mayStore();5950      SMLoc Start = SMLoc::getFromPointer(SymName.data());5951      if (isOutput) {5952        ++InputIdx;5953        OutputDecls.push_back(OpDecl);5954        OutputDeclsAddressOf.push_back(Operand.needAddressOf());5955        OutputConstraints.push_back(("=" + Constraint).str());5956        AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size());5957      } else {5958        InputDecls.push_back(OpDecl);5959        InputDeclsAddressOf.push_back(Operand.needAddressOf());5960        InputConstraints.push_back(Constraint.str());5961        if (Desc.operands()[i - 1].isBranchTarget())5962          AsmStrRewrites.emplace_back(AOK_CallInput, Start, SymName.size());5963        else5964          AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());5965      }5966    }5967 5968    // Consider implicit defs to be clobbers.  Think of cpuid and push.5969    llvm::append_range(ClobberRegs, Desc.implicit_defs());5970  }5971 5972  // Set the number of Outputs and Inputs.5973  NumOutputs = OutputDecls.size();5974  NumInputs = InputDecls.size();5975 5976  // Set the unique clobbers.5977  array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());5978  ClobberRegs.erase(llvm::unique(ClobberRegs), ClobberRegs.end());5979  Clobbers.assign(ClobberRegs.size(), std::string());5980  for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {5981    raw_string_ostream OS(Clobbers[I]);5982    IP->printRegName(OS, ClobberRegs[I]);5983  }5984 5985  // Merge the various outputs and inputs.  Output are expected first.5986  if (NumOutputs || NumInputs) {5987    unsigned NumExprs = NumOutputs + NumInputs;5988    OpDecls.resize(NumExprs);5989    Constraints.resize(NumExprs);5990    for (unsigned i = 0; i < NumOutputs; ++i) {5991      OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]);5992      Constraints[i] = OutputConstraints[i];5993    }5994    for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {5995      OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]);5996      Constraints[j] = InputConstraints[i];5997    }5998  }5999 6000  // Build the IR assembly string.6001  std::string AsmStringIR;6002  raw_string_ostream OS(AsmStringIR);6003  StringRef ASMString =6004      SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();6005  const char *AsmStart = ASMString.begin();6006  const char *AsmEnd = ASMString.end();6007  array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);6008  for (auto I = AsmStrRewrites.begin(), E = AsmStrRewrites.end(); I != E; ++I) {6009    const AsmRewrite &AR = *I;6010    // Check if this has already been covered by another rewrite...6011    if (AR.Done)6012      continue;6013    AsmRewriteKind Kind = AR.Kind;6014 6015    const char *Loc = AR.Loc.getPointer();6016    assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");6017 6018    // Emit everything up to the immediate/expression.6019    if (unsigned Len = Loc - AsmStart)6020      OS << StringRef(AsmStart, Len);6021 6022    // Skip the original expression.6023    if (Kind == AOK_Skip) {6024      AsmStart = Loc + AR.Len;6025      continue;6026    }6027 6028    unsigned AdditionalSkip = 0;6029    // Rewrite expressions in $N notation.6030    switch (Kind) {6031    default:6032      break;6033    case AOK_IntelExpr:6034      assert(AR.IntelExp.isValid() && "cannot write invalid intel expression");6035      if (AR.IntelExp.NeedBracs)6036        OS << "[";6037      if (AR.IntelExp.hasBaseReg())6038        OS << AR.IntelExp.BaseReg;6039      if (AR.IntelExp.hasIndexReg())6040        OS << (AR.IntelExp.hasBaseReg() ? " + " : "")6041           << AR.IntelExp.IndexReg;6042      if (AR.IntelExp.Scale > 1)6043        OS << " * $$" << AR.IntelExp.Scale;6044      if (AR.IntelExp.hasOffset()) {6045        if (AR.IntelExp.hasRegs())6046          OS << " + ";6047        // Fuse this rewrite with a rewrite of the offset name, if present.6048        StringRef OffsetName = AR.IntelExp.OffsetName;6049        SMLoc OffsetLoc = SMLoc::getFromPointer(AR.IntelExp.OffsetName.data());6050        size_t OffsetLen = OffsetName.size();6051        auto rewrite_it = std::find_if(6052            I, AsmStrRewrites.end(), [&](const AsmRewrite &FusingAR) {6053              return FusingAR.Loc == OffsetLoc && FusingAR.Len == OffsetLen &&6054                     (FusingAR.Kind == AOK_Input ||6055                      FusingAR.Kind == AOK_CallInput);6056            });6057        if (rewrite_it == AsmStrRewrites.end()) {6058          OS << "offset " << OffsetName;6059        } else if (rewrite_it->Kind == AOK_CallInput) {6060          OS << "${" << InputIdx++ << ":P}";6061          rewrite_it->Done = true;6062        } else {6063          OS << '$' << InputIdx++;6064          rewrite_it->Done = true;6065        }6066      }6067      if (AR.IntelExp.Imm || AR.IntelExp.emitImm())6068        OS << (AR.IntelExp.emitImm() ? "$$" : " + $$") << AR.IntelExp.Imm;6069      if (AR.IntelExp.NeedBracs)6070        OS << "]";6071      break;6072    case AOK_Label:6073      OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;6074      break;6075    case AOK_Input:6076      OS << '$' << InputIdx++;6077      break;6078    case AOK_CallInput:6079      OS << "${" << InputIdx++ << ":P}";6080      break;6081    case AOK_Output:6082      OS << '$' << OutputIdx++;6083      break;6084    case AOK_SizeDirective:6085      switch (AR.Val) {6086      default: break;6087      case 8:  OS << "byte ptr "; break;6088      case 16: OS << "word ptr "; break;6089      case 32: OS << "dword ptr "; break;6090      case 64: OS << "qword ptr "; break;6091      case 80: OS << "xword ptr "; break;6092      case 128: OS << "xmmword ptr "; break;6093      case 256: OS << "ymmword ptr "; break;6094      }6095      break;6096    case AOK_Emit:6097      OS << ".byte";6098      break;6099    case AOK_Align: {6100      // MS alignment directives are measured in bytes. If the native assembler6101      // measures alignment in bytes, we can pass it straight through.6102      OS << ".align";6103      if (getContext().getAsmInfo()->getAlignmentIsInBytes())6104        break;6105 6106      // Alignment is in log2 form, so print that instead and skip the original6107      // immediate.6108      unsigned Val = AR.Val;6109      OS << ' ' << Val;6110      assert(Val < 10 && "Expected alignment less then 2^10.");6111      AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;6112      break;6113    }6114    case AOK_EVEN:6115      OS << ".even";6116      break;6117    case AOK_EndOfStatement:6118      OS << "\n\t";6119      break;6120    }6121 6122    // Skip the original expression.6123    AsmStart = Loc + AR.Len + AdditionalSkip;6124  }6125 6126  // Emit the remainder of the asm string.6127  if (AsmStart != AsmEnd)6128    OS << StringRef(AsmStart, AsmEnd - AsmStart);6129 6130  AsmString = OS.str();6131  return false;6132}6133 6134void MasmParser::initializeBuiltinSymbolMaps() {6135  // Numeric built-ins (supported in all versions)6136  BuiltinSymbolMap["@version"] = BI_VERSION;6137  BuiltinSymbolMap["@line"] = BI_LINE;6138 6139  // Text built-ins (supported in all versions)6140  BuiltinSymbolMap["@date"] = BI_DATE;6141  BuiltinSymbolMap["@time"] = BI_TIME;6142  BuiltinSymbolMap["@filecur"] = BI_FILECUR;6143  BuiltinSymbolMap["@filename"] = BI_FILENAME;6144  BuiltinSymbolMap["@curseg"] = BI_CURSEG;6145 6146  // Function built-ins (supported in all versions)6147  BuiltinFunctionMap["@catstr"] = BI_CATSTR;6148 6149  // Some built-ins exist only for MASM32 (32-bit x86)6150  if (getContext().getSubtargetInfo()->getTargetTriple().getArch() ==6151      Triple::x86) {6152    // Numeric built-ins6153    // BuiltinSymbolMap["@cpu"] = BI_CPU;6154    // BuiltinSymbolMap["@interface"] = BI_INTERFACE;6155    // BuiltinSymbolMap["@wordsize"] = BI_WORDSIZE;6156    // BuiltinSymbolMap["@codesize"] = BI_CODESIZE;6157    // BuiltinSymbolMap["@datasize"] = BI_DATASIZE;6158    // BuiltinSymbolMap["@model"] = BI_MODEL;6159 6160    // Text built-ins6161    // BuiltinSymbolMap["@code"] = BI_CODE;6162    // BuiltinSymbolMap["@data"] = BI_DATA;6163    // BuiltinSymbolMap["@fardata?"] = BI_FARDATA;6164    // BuiltinSymbolMap["@stack"] = BI_STACK;6165  }6166}6167 6168const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol,6169                                               SMLoc StartLoc) {6170  switch (Symbol) {6171  default:6172    return nullptr;6173  case BI_VERSION:6174    // Match a recent version of ML.EXE.6175    return MCConstantExpr::create(1427, getContext());6176  case BI_LINE: {6177    int64_t Line;6178    if (ActiveMacros.empty())6179      Line = SrcMgr.FindLineNumber(StartLoc, CurBuffer);6180    else6181      Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,6182                                   ActiveMacros.front()->ExitBuffer);6183    return MCConstantExpr::create(Line, getContext());6184  }6185  }6186  llvm_unreachable("unhandled built-in symbol");6187}6188 6189std::optional<std::string>6190MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) {6191  switch (Symbol) {6192  default:6193    return {};6194  case BI_DATE: {6195    // Current local date, formatted MM/DD/YY6196    char TmpBuffer[sizeof("mm/dd/yy")];6197    const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%D", &TM);6198    return std::string(TmpBuffer, Len);6199  }6200  case BI_TIME: {6201    // Current local time, formatted HH:MM:SS (24-hour clock)6202    char TmpBuffer[sizeof("hh:mm:ss")];6203    const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%T", &TM);6204    return std::string(TmpBuffer, Len);6205  }6206  case BI_FILECUR:6207    return SrcMgr6208        .getMemoryBuffer(6209            ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer)6210        ->getBufferIdentifier()6211        .str();6212  case BI_FILENAME:6213    return sys::path::stem(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())6214                               ->getBufferIdentifier())6215        .upper();6216  case BI_CURSEG:6217    return getStreamer().getCurrentSectionOnly()->getName().str();6218  }6219  llvm_unreachable("unhandled built-in symbol");6220}6221 6222bool MasmParser::evaluateBuiltinMacroFunction(BuiltinFunction Function,6223                                              StringRef Name,6224                                              std::string &Res) {6225  if (parseToken(AsmToken::LParen, "invoking macro function '" + Name +6226                                       "' requires arguments in parentheses")) {6227    return true;6228  }6229 6230  MCAsmMacroParameters P;6231  switch (Function) {6232  default:6233    return true;6234  case BI_CATSTR:6235    break;6236  }6237  MCAsmMacro M(Name, "", P, {}, true);6238 6239  MCAsmMacroArguments A;6240  if (parseMacroArguments(&M, A, AsmToken::RParen) || parseRParen()) {6241    return true;6242  }6243 6244  switch (Function) {6245  default:6246    llvm_unreachable("unhandled built-in function");6247  case BI_CATSTR: {6248    for (const MCAsmMacroArgument &Arg : A) {6249      for (const AsmToken &Tok : Arg) {6250        if (Tok.is(AsmToken::String)) {6251          Res.append(Tok.getStringContents());6252        } else {6253          Res.append(Tok.getString());6254        }6255      }6256    }6257    return false;6258  }6259  }6260  llvm_unreachable("unhandled built-in function");6261  return true;6262}6263 6264/// Create an MCAsmParser instance.6265MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C,6266                                      MCStreamer &Out, const MCAsmInfo &MAI,6267                                      struct tm TM, unsigned CB) {6268  return new MasmParser(SM, C, Out, MAI, TM, CB);6269}6270