ARMAsmParser.cpp revision 515d509360d81946247fd0f937034cdf1f237c72
1//===-- ARMAsmParser.cpp - Parse ARM assembly to MCInst instructions ------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ARM.h"
11#include "llvm/ADT/SmallVector.h"
12#include "llvm/ADT/Twine.h"
13#include "llvm/MC/MCAsmLexer.h"
14#include "llvm/MC/MCAsmParser.h"
15#include "llvm/MC/MCStreamer.h"
16#include "llvm/MC/MCExpr.h"
17#include "llvm/MC/MCInst.h"
18#include "llvm/Support/SourceMgr.h"
19#include "llvm/Target/TargetRegistry.h"
20#include "llvm/Target/TargetAsmParser.h"
21using namespace llvm;
22
23namespace {
24struct ARMOperand;
25
26// The shift types for register controlled shifts in arm memory addressing
27enum ShiftType {
28  Lsl,
29  Lsr,
30  Asr,
31  Ror,
32  Rrx
33};
34
35class ARMAsmParser : public TargetAsmParser {
36  MCAsmParser &Parser;
37
38private:
39  MCAsmParser &getParser() const { return Parser; }
40
41  MCAsmLexer &getLexer() const { return Parser.getLexer(); }
42
43  void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); }
44
45  bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); }
46
47  bool ParseRegister(ARMOperand &Op);
48
49  bool ParseRegisterList(ARMOperand &Op);
50
51  bool ParseMemory(ARMOperand &Op);
52
53  bool ParseShift(enum ShiftType *St, const MCExpr *&ShiftAmount);
54
55  bool ParseOperand(ARMOperand &Op);
56
57  bool ParseDirectiveWord(unsigned Size, SMLoc L);
58
59  bool ParseDirectiveThumb(SMLoc L);
60
61  bool ParseDirectiveThumbFunc(SMLoc L);
62
63  bool ParseDirectiveCode(SMLoc L);
64
65  bool ParseDirectiveSyntax(SMLoc L);
66
67  // TODO - For now hacked versions of the next two are in here in this file to
68  // allow some parser testing until the table gen versions are implemented.
69
70  /// @name Auto-generated Match Functions
71  /// {
72  bool MatchInstruction(SmallVectorImpl<ARMOperand> &Operands,
73                        MCInst &Inst);
74
75  /// MatchRegisterName - Match the given string to a register name and return
76  /// its register number, or -1 if there is no match.  To allow return values
77  /// to be used directly in register lists, arm registers have values between
78  /// 0 and 15.
79  int MatchRegisterName(const StringRef &Name);
80
81  /// }
82
83
84public:
85  ARMAsmParser(const Target &T, MCAsmParser &_Parser)
86    : TargetAsmParser(T), Parser(_Parser) {}
87
88  virtual bool ParseInstruction(const StringRef &Name, MCInst &Inst);
89
90  virtual bool ParseDirective(AsmToken DirectiveID);
91};
92
93} // end anonymous namespace
94
95namespace {
96
97/// ARMOperand - Instances of this class represent a parsed ARM machine
98/// instruction.
99struct ARMOperand {
100  enum {
101    Token,
102    Register,
103    Immediate,
104    Memory
105  } Kind;
106
107
108  union {
109    struct {
110      const char *Data;
111      unsigned Length;
112    } Tok;
113
114    struct {
115      unsigned RegNum;
116      bool Writeback;
117    } Reg;
118
119    struct {
120      const MCExpr *Val;
121    } Imm;
122
123    // This is for all forms of ARM address expressions
124    struct {
125      unsigned BaseRegNum;
126      bool OffsetIsReg;
127      const MCExpr *Offset; // used when OffsetIsReg is false
128      unsigned OffsetRegNum; // used when OffsetIsReg is true
129      bool OffsetRegShifted; // only used when OffsetIsReg is true
130      enum ShiftType ShiftType;  // used when OffsetRegShifted is true
131      const MCExpr *ShiftAmount; // used when OffsetRegShifted is true
132      bool Preindexed;
133      bool Postindexed;
134      bool Negative; // only used when OffsetIsReg is true
135      bool Writeback;
136    } Mem;
137
138  };
139
140  StringRef getToken() const {
141    assert(Kind == Token && "Invalid access!");
142    return StringRef(Tok.Data, Tok.Length);
143  }
144
145  unsigned getReg() const {
146    assert(Kind == Register && "Invalid access!");
147    return Reg.RegNum;
148  }
149
150  const MCExpr *getImm() const {
151    assert(Kind == Immediate && "Invalid access!");
152    return Imm.Val;
153  }
154
155  bool isToken() const {return Kind == Token; }
156
157  bool isReg() const { return Kind == Register; }
158
159  void addRegOperands(MCInst &Inst, unsigned N) const {
160    assert(N == 1 && "Invalid number of operands!");
161    Inst.addOperand(MCOperand::CreateReg(getReg()));
162  }
163
164  static ARMOperand CreateToken(StringRef Str) {
165    ARMOperand Res;
166    Res.Kind = Token;
167    Res.Tok.Data = Str.data();
168    Res.Tok.Length = Str.size();
169    return Res;
170  }
171
172  static ARMOperand CreateReg(unsigned RegNum, bool Writeback) {
173    ARMOperand Res;
174    Res.Kind = Register;
175    Res.Reg.RegNum = RegNum;
176    Res.Reg.Writeback = Writeback;
177    return Res;
178  }
179
180  static ARMOperand CreateImm(const MCExpr *Val) {
181    ARMOperand Res;
182    Res.Kind = Immediate;
183    Res.Imm.Val = Val;
184    return Res;
185  }
186
187  static ARMOperand CreateMem(unsigned BaseRegNum, bool OffsetIsReg,
188                              const MCExpr *Offset, unsigned OffsetRegNum,
189                              bool OffsetRegShifted, enum ShiftType ShiftType,
190                              const MCExpr *ShiftAmount, bool Preindexed,
191                              bool Postindexed, bool Negative, bool Writeback) {
192    ARMOperand Res;
193    Res.Kind = Memory;
194    Res.Mem.BaseRegNum = BaseRegNum;
195    Res.Mem.OffsetIsReg = OffsetIsReg;
196    Res.Mem.Offset = Offset;
197    Res.Mem.OffsetRegNum = OffsetRegNum;
198    Res.Mem.OffsetRegShifted = OffsetRegShifted;
199    Res.Mem.ShiftType = ShiftType;
200    Res.Mem.ShiftAmount = ShiftAmount;
201    Res.Mem.Preindexed = Preindexed;
202    Res.Mem.Postindexed = Postindexed;
203    Res.Mem.Negative = Negative;
204    Res.Mem.Writeback = Writeback;
205    return Res;
206  }
207};
208
209} // end anonymous namespace.
210
211// Try to parse a register name.  The token must be an Identifier when called,
212// and if it is a register name a Reg operand is created, the token is eaten
213// and false is returned.  Else true is returned and no token is eaten.
214// TODO this is likely to change to allow different register types and or to
215// parse for a specific register type.
216bool ARMAsmParser::ParseRegister(ARMOperand &Op) {
217  const AsmToken &Tok = getLexer().getTok();
218  assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
219
220  // FIXME: Validate register for the current architecture; we have to do
221  // validation later, so maybe there is no need for this here.
222  int RegNum;
223
224  RegNum = MatchRegisterName(Tok.getString());
225  if (RegNum == -1)
226    return true;
227  getLexer().Lex(); // Eat identifier token.
228
229  bool Writeback = false;
230  const AsmToken &ExclaimTok = getLexer().getTok();
231  if (ExclaimTok.is(AsmToken::Exclaim)) {
232    Writeback = true;
233    getLexer().Lex(); // Eat exclaim token
234  }
235
236  Op = ARMOperand::CreateReg(RegNum, Writeback);
237
238  return false;
239}
240
241// Parse a register list, return false if successful else return true or an
242// error.  The first token must be a '{' when called.
243bool ARMAsmParser::ParseRegisterList(ARMOperand &Op) {
244  assert(getLexer().getTok().is(AsmToken::LCurly) &&
245         "Token is not an Left Curly Brace");
246  getLexer().Lex(); // Eat left curly brace token.
247
248  const AsmToken &RegTok = getLexer().getTok();
249  SMLoc RegLoc = RegTok.getLoc();
250  if (RegTok.isNot(AsmToken::Identifier))
251    return Error(RegLoc, "register expected");
252  int RegNum = MatchRegisterName(RegTok.getString());
253  if (RegNum == -1)
254    return Error(RegLoc, "register expected");
255  getLexer().Lex(); // Eat identifier token.
256  unsigned RegList = 1 << RegNum;
257
258  int HighRegNum = RegNum;
259  // TODO ranges like "{Rn-Rm}"
260  while (getLexer().getTok().is(AsmToken::Comma)) {
261    getLexer().Lex(); // Eat comma token.
262
263    const AsmToken &RegTok = getLexer().getTok();
264    SMLoc RegLoc = RegTok.getLoc();
265    if (RegTok.isNot(AsmToken::Identifier))
266      return Error(RegLoc, "register expected");
267    int RegNum = MatchRegisterName(RegTok.getString());
268    if (RegNum == -1)
269      return Error(RegLoc, "register expected");
270
271    if (RegList & (1 << RegNum))
272      Warning(RegLoc, "register duplicated in register list");
273    else if (RegNum <= HighRegNum)
274      Warning(RegLoc, "register not in ascending order in register list");
275    RegList |= 1 << RegNum;
276    HighRegNum = RegNum;
277
278    getLexer().Lex(); // Eat identifier token.
279  }
280  const AsmToken &RCurlyTok = getLexer().getTok();
281  if (RCurlyTok.isNot(AsmToken::RCurly))
282    return Error(RCurlyTok.getLoc(), "'}' expected");
283  getLexer().Lex(); // Eat left curly brace token.
284
285  return false;
286}
287
288// Parse an arm memory expression, return false if successful else return true
289// or an error.  The first token must be a '[' when called.
290// TODO Only preindexing and postindexing addressing are started, unindexed
291// with option, etc are still to do.
292bool ARMAsmParser::ParseMemory(ARMOperand &Op) {
293  assert(getLexer().getTok().is(AsmToken::LBrac) &&
294         "Token is not an Left Bracket");
295  getLexer().Lex(); // Eat left bracket token.
296
297  const AsmToken &BaseRegTok = getLexer().getTok();
298  if (BaseRegTok.isNot(AsmToken::Identifier))
299    return Error(BaseRegTok.getLoc(), "register expected");
300  int BaseRegNum = MatchRegisterName(BaseRegTok.getString());
301  if (BaseRegNum == -1)
302    return Error(BaseRegTok.getLoc(), "register expected");
303  getLexer().Lex(); // Eat identifier token.
304
305  bool Preindexed = false;
306  bool Postindexed = false;
307  bool OffsetIsReg = false;
308  bool Negative = false;
309  bool Writeback = false;
310
311  // First look for preindexed address forms:
312  //  [Rn, +/-Rm]
313  //  [Rn, #offset]
314  //  [Rn, +/-Rm, shift]
315  // that is after the "[Rn" we now have see if the next token is a comma.
316  const AsmToken &Tok = getLexer().getTok();
317  if (Tok.is(AsmToken::Comma)) {
318    Preindexed = true;
319    getLexer().Lex(); // Eat comma token.
320
321    const AsmToken &NextTok = getLexer().getTok();
322    if (NextTok.is(AsmToken::Plus))
323      getLexer().Lex(); // Eat plus token.
324    else if (NextTok.is(AsmToken::Minus)) {
325      Negative = true;
326      getLexer().Lex(); // Eat minus token
327    }
328
329    // See if there is a register following the "[Rn," we have so far.
330    const AsmToken &OffsetRegTok = getLexer().getTok();
331    int OffsetRegNum = MatchRegisterName(OffsetRegTok.getString());
332    bool OffsetRegShifted = false;
333    enum ShiftType ShiftType;
334    const MCExpr *ShiftAmount;
335    const MCExpr *Offset;
336    if (OffsetRegNum != -1) {
337      OffsetIsReg = true;
338      getLexer().Lex(); // Eat identifier token for the offset register.
339      // Look for a comma then a shift
340      const AsmToken &Tok = getLexer().getTok();
341      if (Tok.is(AsmToken::Comma)) {
342        getLexer().Lex(); // Eat comma token.
343
344        const AsmToken &Tok = getLexer().getTok();
345        if (ParseShift(&ShiftType, ShiftAmount))
346          return Error(Tok.getLoc(), "shift expected");
347        OffsetRegShifted = true;
348      }
349    }
350    else { // "[Rn," we have so far was not followed by "Rm"
351      // Look for #offset following the "[Rn,"
352      const AsmToken &HashTok = getLexer().getTok();
353      if (HashTok.isNot(AsmToken::Hash))
354        return Error(HashTok.getLoc(), "'#' expected");
355      getLexer().Lex(); // Eat hash token.
356
357      if (getParser().ParseExpression(Offset))
358       return true;
359    }
360    const AsmToken &RBracTok = getLexer().getTok();
361    if (RBracTok.isNot(AsmToken::RBrac))
362      return Error(RBracTok.getLoc(), "']' expected");
363    getLexer().Lex(); // Eat right bracket token.
364
365    const AsmToken &ExclaimTok = getLexer().getTok();
366    if (ExclaimTok.is(AsmToken::Exclaim)) {
367      Writeback = true;
368      getLexer().Lex(); // Eat exclaim token
369    }
370    Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum,
371                               OffsetRegShifted, ShiftType, ShiftAmount,
372                               Preindexed, Postindexed, Negative, Writeback);
373    return false;
374  }
375  // The "[Rn" we have so far was not followed by a comma.
376  else if (Tok.is(AsmToken::RBrac)) {
377    // This is a post indexing addressing forms:
378    //  [Rn], #offset
379    //  [Rn], +/-Rm
380    //  [Rn], +/-Rm, shift
381    // that is a ']' follows after the "[Rn".
382    Postindexed = true;
383    Writeback = true;
384    getLexer().Lex(); // Eat right bracket token.
385
386    const AsmToken &CommaTok = getLexer().getTok();
387    if (CommaTok.isNot(AsmToken::Comma))
388      return Error(CommaTok.getLoc(), "',' expected");
389    getLexer().Lex(); // Eat comma token.
390
391    const AsmToken &NextTok = getLexer().getTok();
392    if (NextTok.is(AsmToken::Plus))
393      getLexer().Lex(); // Eat plus token.
394    else if (NextTok.is(AsmToken::Minus)) {
395      Negative = true;
396      getLexer().Lex(); // Eat minus token
397    }
398
399    // See if there is a register following the "[Rn]," we have so far.
400    const AsmToken &OffsetRegTok = getLexer().getTok();
401    int OffsetRegNum = MatchRegisterName(OffsetRegTok.getString());
402    bool OffsetRegShifted = false;
403    enum ShiftType ShiftType;
404    const MCExpr *ShiftAmount;
405    const MCExpr *Offset;
406    if (OffsetRegNum != -1) {
407      OffsetIsReg = true;
408      getLexer().Lex(); // Eat identifier token for the offset register.
409      // Look for a comma then a shift
410      const AsmToken &Tok = getLexer().getTok();
411      if (Tok.is(AsmToken::Comma)) {
412        getLexer().Lex(); // Eat comma token.
413
414        const AsmToken &Tok = getLexer().getTok();
415        if (ParseShift(&ShiftType, ShiftAmount))
416          return Error(Tok.getLoc(), "shift expected");
417        OffsetRegShifted = true;
418      }
419    }
420    else { // "[Rn]," we have so far was not followed by "Rm"
421      // Look for #offset following the "[Rn],"
422      const AsmToken &HashTok = getLexer().getTok();
423      if (HashTok.isNot(AsmToken::Hash))
424        return Error(HashTok.getLoc(), "'#' expected");
425      getLexer().Lex(); // Eat hash token.
426
427      if (getParser().ParseExpression(Offset))
428       return true;
429    }
430    Op = ARMOperand::CreateMem(BaseRegNum, OffsetIsReg, Offset, OffsetRegNum,
431                               OffsetRegShifted, ShiftType, ShiftAmount,
432                               Preindexed, Postindexed, Negative, Writeback);
433    return false;
434  }
435
436  return true;
437}
438
439/// ParseShift as one of these two:
440///   ( lsl | lsr | asr | ror ) , # shift_amount
441///   rrx
442/// and returns true if it parses a shift otherwise it returns false.
443bool ARMAsmParser::ParseShift(ShiftType *St, const MCExpr *&ShiftAmount) {
444  const AsmToken &Tok = getLexer().getTok();
445  if (Tok.isNot(AsmToken::Identifier))
446    return true;
447  const StringRef &ShiftName = Tok.getString();
448  if (ShiftName == "lsl" || ShiftName == "LSL")
449    *St = Lsl;
450  else if (ShiftName == "lsr" || ShiftName == "LSR")
451    *St = Lsr;
452  else if (ShiftName == "asr" || ShiftName == "ASR")
453    *St = Asr;
454  else if (ShiftName == "ror" || ShiftName == "ROR")
455    *St = Ror;
456  else if (ShiftName == "rrx" || ShiftName == "RRX")
457    *St = Rrx;
458  else
459    return true;
460  getLexer().Lex(); // Eat shift type token.
461
462  // For all but a Rotate right there must be a '#' and a shift amount
463  if (*St != Rrx) {
464    // Look for # following the shift type
465    const AsmToken &HashTok = getLexer().getTok();
466    if (HashTok.isNot(AsmToken::Hash))
467      return Error(HashTok.getLoc(), "'#' expected");
468    getLexer().Lex(); // Eat hash token.
469
470    if (getParser().ParseExpression(ShiftAmount))
471      return true;
472  }
473
474  return false;
475}
476
477// A hack to allow some testing, to be replaced by a real table gen version.
478int ARMAsmParser::MatchRegisterName(const StringRef &Name) {
479  if (Name == "r0" || Name == "R0")
480    return 0;
481  else if (Name == "r1" || Name == "R1")
482    return 1;
483  else if (Name == "r2" || Name == "R2")
484    return 2;
485  else if (Name == "r3" || Name == "R3")
486    return 3;
487  else if (Name == "r3" || Name == "R3")
488    return 3;
489  else if (Name == "r4" || Name == "R4")
490    return 4;
491  else if (Name == "r5" || Name == "R5")
492    return 5;
493  else if (Name == "r6" || Name == "R6")
494    return 6;
495  else if (Name == "r7" || Name == "R7")
496    return 7;
497  else if (Name == "r8" || Name == "R8")
498    return 8;
499  else if (Name == "r9" || Name == "R9")
500    return 9;
501  else if (Name == "r10" || Name == "R10")
502    return 10;
503  else if (Name == "r11" || Name == "R11" || Name == "fp")
504    return 11;
505  else if (Name == "r12" || Name == "R12" || Name == "ip")
506    return 12;
507  else if (Name == "r13" || Name == "R13" || Name == "sp")
508    return 13;
509  else if (Name == "r14" || Name == "R14" || Name == "lr")
510      return 14;
511  else if (Name == "r15" || Name == "R15" || Name == "pc")
512    return 15;
513  return -1;
514}
515
516// A hack to allow some testing, to be replaced by a real table gen version.
517bool ARMAsmParser::MatchInstruction(SmallVectorImpl<ARMOperand> &Operands,
518                                    MCInst &Inst) {
519  struct ARMOperand Op0 = Operands[0];
520  assert(Op0.Kind == ARMOperand::Token && "First operand not a Token");
521  const StringRef &Mnemonic = Op0.getToken();
522  if (Mnemonic == "add" ||
523      Mnemonic == "stmfd" ||
524      Mnemonic == "str" ||
525      Mnemonic == "ldmfd" ||
526      Mnemonic == "ldr" ||
527      Mnemonic == "mov" ||
528      Mnemonic == "sub" ||
529      Mnemonic == "bl" ||
530      Mnemonic == "push" ||
531      Mnemonic == "blx" ||
532      Mnemonic == "pop")
533    return false;
534
535  return true;
536}
537
538// Parse a arm instruction operand.  For now this parses the operand regardless
539// of the mnemonic.
540bool ARMAsmParser::ParseOperand(ARMOperand &Op) {
541  switch (getLexer().getKind()) {
542  case AsmToken::Identifier:
543    if (!ParseRegister(Op))
544      return false;
545    // This was not a register so parse other operands that start with an
546    // identifier (like labels) as expressions and create them as immediates.
547    const MCExpr *IdVal;
548    if (getParser().ParseExpression(IdVal))
549      return true;
550    Op = ARMOperand::CreateImm(IdVal);
551    return false;
552  case AsmToken::LBrac:
553    return ParseMemory(Op);
554  case AsmToken::LCurly:
555    return ParseRegisterList(Op);
556  case AsmToken::Hash:
557    // #42 -> immediate.
558    // TODO: ":lower16:" and ":upper16:" modifiers after # before immediate
559    getLexer().Lex();
560    const MCExpr *ImmVal;
561    if (getParser().ParseExpression(ImmVal))
562      return true;
563    Op = ARMOperand::CreateImm(ImmVal);
564    return false;
565  default:
566    return Error(getLexer().getTok().getLoc(), "unexpected token in operand");
567  }
568}
569
570// Parse an arm instruction mnemonic followed by its operands.
571bool ARMAsmParser::ParseInstruction(const StringRef &Name, MCInst &Inst) {
572  SmallVector<ARMOperand, 7> Operands;
573
574  Operands.push_back(ARMOperand::CreateToken(Name));
575
576  SMLoc Loc = getLexer().getTok().getLoc();
577  if (getLexer().isNot(AsmToken::EndOfStatement)) {
578
579    // Read the first operand.
580    Operands.push_back(ARMOperand());
581    if (ParseOperand(Operands.back()))
582      return true;
583
584    while (getLexer().is(AsmToken::Comma)) {
585      getLexer().Lex();  // Eat the comma.
586
587      // Parse and remember the operand.
588      Operands.push_back(ARMOperand());
589      if (ParseOperand(Operands.back()))
590        return true;
591    }
592  }
593  if (!MatchInstruction(Operands, Inst))
594    return false;
595
596  Error(Loc, "ARMAsmParser::ParseInstruction only partly implemented");
597  return true;
598}
599
600/// ParseDirective parses the arm specific directives
601bool ARMAsmParser::ParseDirective(AsmToken DirectiveID) {
602  StringRef IDVal = DirectiveID.getIdentifier();
603  if (IDVal == ".word")
604    return ParseDirectiveWord(4, DirectiveID.getLoc());
605  else if (IDVal == ".thumb")
606    return ParseDirectiveThumb(DirectiveID.getLoc());
607  else if (IDVal == ".thumb_func")
608    return ParseDirectiveThumbFunc(DirectiveID.getLoc());
609  else if (IDVal == ".code")
610    return ParseDirectiveCode(DirectiveID.getLoc());
611  else if (IDVal == ".syntax")
612    return ParseDirectiveSyntax(DirectiveID.getLoc());
613  return true;
614}
615
616/// ParseDirectiveWord
617///  ::= .word [ expression (, expression)* ]
618bool ARMAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) {
619  if (getLexer().isNot(AsmToken::EndOfStatement)) {
620    for (;;) {
621      const MCExpr *Value;
622      if (getParser().ParseExpression(Value))
623        return true;
624
625      getParser().getStreamer().EmitValue(Value, Size);
626
627      if (getLexer().is(AsmToken::EndOfStatement))
628        break;
629
630      // FIXME: Improve diagnostic.
631      if (getLexer().isNot(AsmToken::Comma))
632        return Error(L, "unexpected token in directive");
633      getLexer().Lex();
634    }
635  }
636
637  getLexer().Lex();
638  return false;
639}
640
641/// ParseDirectiveThumb
642///  ::= .thumb
643bool ARMAsmParser::ParseDirectiveThumb(SMLoc L) {
644  if (getLexer().isNot(AsmToken::EndOfStatement))
645    return Error(L, "unexpected token in directive");
646  getLexer().Lex();
647
648  // TODO: set thumb mode
649  // TODO: tell the MC streamer the mode
650  // getParser().getStreamer().Emit???();
651  return false;
652}
653
654/// ParseDirectiveThumbFunc
655///  ::= .thumbfunc symbol_name
656bool ARMAsmParser::ParseDirectiveThumbFunc(SMLoc L) {
657  const AsmToken &Tok = getLexer().getTok();
658  if (Tok.isNot(AsmToken::Identifier) && Tok.isNot(AsmToken::String))
659    return Error(L, "unexpected token in .syntax directive");
660  StringRef SymbolName = getLexer().getTok().getIdentifier();
661  getLexer().Lex(); // Consume the identifier token.
662
663  if (getLexer().isNot(AsmToken::EndOfStatement))
664    return Error(L, "unexpected token in directive");
665  getLexer().Lex();
666
667  // TODO: mark symbol as a thumb symbol
668  // getParser().getStreamer().Emit???();
669  return false;
670}
671
672/// ParseDirectiveSyntax
673///  ::= .syntax unified | divided
674bool ARMAsmParser::ParseDirectiveSyntax(SMLoc L) {
675  const AsmToken &Tok = getLexer().getTok();
676  if (Tok.isNot(AsmToken::Identifier))
677    return Error(L, "unexpected token in .syntax directive");
678  const StringRef &Mode = Tok.getString();
679  bool unified_syntax;
680  if (Mode == "unified" || Mode == "UNIFIED") {
681    getLexer().Lex();
682    unified_syntax = true;
683  }
684  else if (Mode == "divided" || Mode == "DIVIDED") {
685    getLexer().Lex();
686    unified_syntax = false;
687  }
688  else
689    return Error(L, "unrecognized syntax mode in .syntax directive");
690
691  if (getLexer().isNot(AsmToken::EndOfStatement))
692    return Error(getLexer().getTok().getLoc(), "unexpected token in directive");
693  getLexer().Lex();
694
695  // TODO tell the MC streamer the mode
696  // getParser().getStreamer().Emit???();
697  return false;
698}
699
700/// ParseDirectiveCode
701///  ::= .code 16 | 32
702bool ARMAsmParser::ParseDirectiveCode(SMLoc L) {
703  const AsmToken &Tok = getLexer().getTok();
704  if (Tok.isNot(AsmToken::Integer))
705    return Error(L, "unexpected token in .code directive");
706  int64_t Val = getLexer().getTok().getIntVal();
707  bool thumb_mode;
708  if (Val == 16) {
709    getLexer().Lex();
710    thumb_mode = true;
711  }
712  else if (Val == 32) {
713    getLexer().Lex();
714    thumb_mode = false;
715  }
716  else
717    return Error(L, "invalid operand to .code directive");
718
719  if (getLexer().isNot(AsmToken::EndOfStatement))
720    return Error(getLexer().getTok().getLoc(), "unexpected token in directive");
721  getLexer().Lex();
722
723  // TODO tell the MC streamer the mode
724  // getParser().getStreamer().Emit???();
725  return false;
726}
727
728// Force static initialization.
729extern "C" void LLVMInitializeARMAsmParser() {
730  RegisterAsmParser<ARMAsmParser> X(TheARMTarget);
731  RegisterAsmParser<ARMAsmParser> Y(TheThumbTarget);
732}
733