From d3d1cad535d1c88e13e8e082c136260ee624967f Mon Sep 17 00:00:00 2001 From: David Greene Date: Wed, 19 Oct 2011 13:04:43 +0000 Subject: [PATCH] Implement Paste Add a paste operator '#' to take two identifier-like strings and joint them. Internally paste gets represented as a !strconcat() with any necessary casts to string added. This will be used to implement basic for loop functionality as in: for i = [0, 1, 2, 3, 4, 5, 6, 7] { def R#i : Register<...> } git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@142525 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/TableGen/TGLexer.cpp | 10 +++--- lib/TableGen/TGLexer.h | 3 +- lib/TableGen/TGParser.cpp | 82 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/lib/TableGen/TGLexer.cpp b/lib/TableGen/TGLexer.cpp index 3262121ee8d..45d0b1ed2b0 100644 --- a/lib/TableGen/TGLexer.cpp +++ b/lib/TableGen/TGLexer.cpp @@ -91,10 +91,10 @@ tgtok::TokKind TGLexer::LexToken() { switch (CurChar) { default: - // Handle letters: [a-zA-Z_#] - if (isalpha(CurChar) || CurChar == '_' || CurChar == '#') + // Handle letters: [a-zA-Z_] + if (isalpha(CurChar) || CurChar == '_') return LexIdentifier(); - + // Unknown character, emit an error. return ReturnError(TokStart, "Unexpected character"); case EOF: return tgtok::Eof; @@ -111,6 +111,7 @@ tgtok::TokKind TGLexer::LexToken() { case ')': return tgtok::r_paren; case '=': return tgtok::equal; case '?': return tgtok::question; + case '#': return tgtok::paste; case 0: case ' ': @@ -250,8 +251,7 @@ tgtok::TokKind TGLexer::LexIdentifier() { const char *IdentStart = TokStart; // Match the rest of the identifier regex: [0-9a-zA-Z_#]* - while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_' || - *CurPtr == '#') + while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_') ++CurPtr; // Check to see if this identifier is a keyword. diff --git a/lib/TableGen/TGLexer.h b/lib/TableGen/TGLexer.h index 24f8ea4ce5a..0246ab6b900 100644 --- a/lib/TableGen/TGLexer.h +++ b/lib/TableGen/TGLexer.h @@ -39,7 +39,8 @@ namespace tgtok { colon, semi, // : ; comma, period, // , . equal, question, // = ? - + paste, // # + // Keywords. Bit, Bits, Class, Code, Dag, Def, Defm, Field, In, Int, Let, List, MultiClass, String, diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp index 53e4fdcae0d..c06add4f618 100644 --- a/lib/TableGen/TGParser.cpp +++ b/lib/TableGen/TGParser.cpp @@ -1083,6 +1083,12 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, Init *R = 0; switch (Lex.getCode()) { default: TokError("Unknown token when parsing a value"); break; + case tgtok::paste: + // This is a leading paste operation. This is deprecated but + // still exists in some .td files. Ignore it. + Lex.Lex(); // Skip '#'. + return ParseSimpleValue(CurRec, ItemType, Mode); + break; case tgtok::IntVal: R = IntInit::get(Lex.getCurIntVal()); Lex.Lex(); break; case tgtok::StrVal: { std::string Val = Lex.getCurStrVal(); @@ -1410,6 +1416,56 @@ Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) { Result = FieldInit::get(Result, Lex.getCurStrVal()); Lex.Lex(); // eat field name break; + + case tgtok::paste: + SMLoc PasteLoc = Lex.getLoc(); + + // Create a !strconcat() operation, first casting each operand to + // a string if necessary. + + TypedInit *LHS = dynamic_cast(Result); + if (!LHS) { + Error(PasteLoc, "LHS of paste is not typed!"); + return 0; + } + + if (LHS->getType() != StringRecTy::get()) { + LHS = UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get()); + } + + TypedInit *RHS = 0; + + Lex.Lex(); // Eat the '#'. + switch (Lex.getCode()) { + case tgtok::colon: + case tgtok::semi: + case tgtok::l_brace: + // These are all of the tokens that can begin an object body. + // Some of these can also begin values but we disallow those cases + // because they are unlikely to be useful. + + // Trailing paste, concat with an empty string. + RHS = StringInit::get(""); + break; + + default: + Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode); + RHS = dynamic_cast(RHSResult); + if (!RHS) { + Error(PasteLoc, "RHS of paste is not typed!"); + return 0; + } + + if (RHS->getType() != StringRecTy::get()) { + RHS = UnOpInit::get(UnOpInit::CAST, RHS, StringRecTy::get()); + } + + break; + } + + Result = BinOpInit::get(BinOpInit::STRCONCAT, LHS, RHS, + StringRecTy::get())->Fold(CurRec, CurMultiClass); + break; } } } @@ -1979,41 +2035,23 @@ InstantiateMulticlassDef(MultiClass &MC, // instantiated def a unique name. Otherwise, if "#NAME#" exists in the // name, substitute the prefix for #NAME#. Otherwise, use the defm name // as a prefix. - StringInit *DefNameString = - dynamic_cast(DefProto->getNameInit()); - - if (DefNameString == 0) { - Error(DefmPrefixLoc, "Def name is not a string"); - return 0; - } if (DefmPrefix == 0) DefmPrefix = StringInit::get(GetNewAnonymousName()); Init *DefName = DefProto->getNameInit(); - // See if we can substitute #NAME#. - Init *NewDefName = - TernOpInit::get(TernOpInit::SUBST, - StringInit::get("#NAME#"), - DefmPrefix, - DefName, - StringRecTy::get())->Fold(DefProto, &MC); - - if (NewDefName == DefName) { - // We did't do any substitution. We should concatenate the given - // prefix and name. - if (DefmPrefix == 0) - DefmPrefix = StringInit::get(GetNewAnonymousName()); + StringInit *DefNameString = dynamic_cast(DefName); + if (DefNameString != 0) { + // We have a fully expanded string so there are no operators to + // resolve. We should concatenate the given prefix and name. DefName = BinOpInit::get(BinOpInit::STRCONCAT, UnOpInit::get(UnOpInit::CAST, DefmPrefix, StringRecTy::get())->Fold(DefProto, &MC), DefName, StringRecTy::get())->Fold(DefProto, &MC); } - else - DefName = NewDefName; Record *CurRec = new Record(DefName, DefmPrefixLoc, Records); -- 2.11.0