summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Greene <greened@obbligato.org>2009-05-14 22:38:31 +0000
committerDavid Greene <greened@obbligato.org>2009-05-14 22:38:31 +0000
commit5f9f9ba00b85eb19da2618f393e43a6a11b5d892 (patch)
treebd237c2d0cb6a5ec6c114294dfdb5bd049d1501a
parentbeb31a51f67f651c5fa3c5094a78266d04a697a5 (diff)
downloadllvm-5f9f9ba00b85eb19da2618f393e43a6a11b5d892.tar.gz
llvm-5f9f9ba00b85eb19da2618f393e43a6a11b5d892.tar.bz2
llvm-5f9f9ba00b85eb19da2618f393e43a6a11b5d892.tar.xz
Graduate LLVM to the big leagues by embedding a LISP processor into TableGen.
Ok, not really, but do support some common LISP functions: * car * cdr * null git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@71805 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/TableGenFundamentals.html6
-rw-r--r--test/TableGen/lisp.td21
-rw-r--r--utils/TableGen/Record.cpp38
-rw-r--r--utils/TableGen/Record.h10
-rw-r--r--utils/TableGen/TGLexer.cpp3
-rw-r--r--utils/TableGen/TGLexer.h2
-rw-r--r--utils/TableGen/TGParser.cpp75
7 files changed, 149 insertions, 6 deletions
diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html
index 9607f9ea9e..36798c8b8b 100644
--- a/docs/TableGenFundamentals.html
+++ b/docs/TableGenFundamentals.html
@@ -411,6 +411,12 @@ aborts with an error. </dd>
<dd>For each member 'b' of dag or list 'a' apply operator 'c.' 'b' is a
dummy variable that should be declared as a member variable of an instantiated
class. This operation is analogous to $(foreach) in GNU make.</dd>
+<dt><tt>!car(a)</tt></dt>
+ <dd>The first element of list 'a.'</dd>
+<dt><tt>!cdr(a)</tt></dt>
+ <dd>The 2nd-N elements of list 'a.'</dd>
+<dt><tt>!null(a)</tt></dt>
+ <dd>An integer {0,1} indicating whether list 'a' is empty.</dd>
</dl>
<p>Note that all of the values have rules specifying how they convert to values
diff --git a/test/TableGen/lisp.td b/test/TableGen/lisp.td
new file mode 100644
index 0000000000..3e392fda84
--- /dev/null
+++ b/test/TableGen/lisp.td
@@ -0,0 +1,21 @@
+// RUN: tblgen %s | grep {}
+
+class List<list<string> n> {
+ list<string> names = n;
+}
+
+class CAR<string e> {
+ string element = e;
+}
+
+class CDR<list<string> r, int n> {
+ list<string> rest = r;
+ int null = n;
+}
+
+class NameList<list<string> Names> :
+ List<Names>, CAR<!car(Names)>, CDR<!cdr(Names), !null(!cdr(Names))>;
+
+def Three : NameList<["Tom", "Dick", "Harry"]>;
+
+def One : NameList<["Jeffrey Sinclair"]>;
diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp
index ade17026fb..ae2c2f3ea4 100644
--- a/utils/TableGen/Record.cpp
+++ b/utils/TableGen/Record.cpp
@@ -520,6 +520,41 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) {
}
break;
}
+ case CAR: {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ if (LHSl) {
+ if (LHSl->getSize() == 0) {
+ assert(0 && "Empty list in car");
+ return 0;
+ }
+ return LHSl->getElement(0);
+ }
+ break;
+ }
+ case CDR: {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ if (LHSl) {
+ if (LHSl->getSize() == 0) {
+ assert(0 && "Empty list in cdr");
+ return 0;
+ }
+ ListInit *Result = new ListInit(LHSl->begin()+1, LHSl->end());
+ return Result;
+ }
+ break;
+ }
+ case LNULL: {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ if (LHSl) {
+ if (LHSl->getSize() == 0) {
+ return new IntInit(1);
+ }
+ else {
+ return new IntInit(0);
+ }
+ }
+ break;
+ }
}
return this;
}
@@ -536,6 +571,9 @@ std::string UnOpInit::getAsString() const {
std::string Result;
switch (Opc) {
case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break;
+ case CAR: Result = "!car"; break;
+ case CDR: Result = "!cdr"; break;
+ case LNULL: Result = "!null"; break;
}
return Result + "(" + LHS->getAsString() + ")";
}
diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h
index c37f6e6207..c2549dab73 100644
--- a/utils/TableGen/Record.h
+++ b/utils/TableGen/Record.h
@@ -690,9 +690,14 @@ public:
class ListInit : public Init {
std::vector<Init*> Values;
public:
+ typedef std::vector<Init*>::iterator iterator;
+ typedef std::vector<Init*>::const_iterator const_iterator;
+
explicit ListInit(std::vector<Init*> &Vs) {
Values.swap(Vs);
}
+ explicit ListInit(iterator Start, iterator End)
+ : Values(Start, End) {}
unsigned getSize() const { return Values.size(); }
Init *getElement(unsigned i) const {
@@ -717,9 +722,6 @@ public:
virtual std::string getAsString() const;
- typedef std::vector<Init*>::iterator iterator;
- typedef std::vector<Init*>::const_iterator const_iterator;
-
inline iterator begin() { return Values.begin(); }
inline const_iterator begin() const { return Values.begin(); }
inline iterator end () { return Values.end(); }
@@ -761,7 +763,7 @@ public:
///
class UnOpInit : public OpInit {
public:
- enum UnaryOp { CAST };
+ enum UnaryOp { CAST, CAR, CDR, LNULL };
private:
UnaryOp Opc;
Init *LHS;
diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp
index 6215a7267f..faf1e75a68 100644
--- a/utils/TableGen/TGLexer.cpp
+++ b/utils/TableGen/TGLexer.cpp
@@ -450,6 +450,9 @@ tgtok::TokKind TGLexer::LexExclaim() {
if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst;
if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach;
if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast;
+ if (Len == 3 && !memcmp(Start, "car", 3)) return tgtok::XCar;
+ if (Len == 3 && !memcmp(Start, "cdr", 3)) return tgtok::XCdr;
+ if (Len == 4 && !memcmp(Start, "null", 4)) return tgtok::XNull;
return ReturnError(Start-1, "Unknown operator");
}
diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h
index 3993e89d64..3d27e5e8ed 100644
--- a/utils/TableGen/TGLexer.h
+++ b/utils/TableGen/TGLexer.h
@@ -46,7 +46,7 @@ namespace tgtok {
// !keywords.
XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst,
- XForEach,
+ XForEach, XCar, XCdr, XNull,
// Integer value.
IntVal,
diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp
index bc5d65eea5..8ff25a6186 100644
--- a/utils/TableGen/TGParser.cpp
+++ b/utils/TableGen/TGParser.cpp
@@ -680,6 +680,9 @@ Init *TGParser::ParseOperation(Record *CurRec) {
TokError("unknown operation");
return 0;
break;
+ case tgtok::XCar:
+ case tgtok::XCdr:
+ case tgtok::XNull:
case tgtok::XCast: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code;
RecTy *Type = 0;
@@ -693,11 +696,24 @@ Init *TGParser::ParseOperation(Record *CurRec) {
Type = ParseOperatorType();
if (Type == 0) {
- TokError("did not get type for binary operator");
+ TokError("did not get type for unary operator");
return 0;
}
break;
+ case tgtok::XCar:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::CAR;
+ break;
+ case tgtok::XCdr:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::CDR;
+ break;
+ case tgtok::XNull:
+ Lex.Lex(); // eat the operation
+ Code = UnOpInit::LNULL;
+ Type = new IntRecTy;
+ break;
}
if (Lex.getCode() != tgtok::l_paren) {
TokError("expected '(' after unary operator");
@@ -708,6 +724,60 @@ Init *TGParser::ParseOperation(Record *CurRec) {
Init *LHS = ParseValue(CurRec);
if (LHS == 0) return 0;
+ if (Code == UnOpInit::CAR
+ || Code == UnOpInit::CDR
+ || Code == UnOpInit::LNULL) {
+ ListInit *LHSl = dynamic_cast<ListInit*>(LHS);
+ TypedInit *LHSt = dynamic_cast<TypedInit*>(LHS);
+ if (LHSl == 0 && LHSt == 0) {
+ TokError("expected list type argument in unary operator");
+ return 0;
+ }
+ if (LHSt) {
+ ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType());
+ if (LType == 0) {
+ TokError("expected list type argumnet in unary operator");
+ return 0;
+ }
+ }
+
+ if (Code == UnOpInit::CAR
+ || Code == UnOpInit::CDR) {
+ if (LHSl && LHSl->getSize() == 0) {
+ TokError("empty list argument in unary operator");
+ return 0;
+ }
+ if (LHSl) {
+ Init *Item = LHSl->getElement(0);
+ TypedInit *Itemt = dynamic_cast<TypedInit*>(Item);
+ if (Itemt == 0) {
+ TokError("untyped list element in unary operator");
+ return 0;
+ }
+ if (Code == UnOpInit::CAR) {
+ Type = Itemt->getType();
+ }
+ else {
+ Type = new ListRecTy(Itemt->getType());
+ }
+ }
+ else {
+ assert(LHSt && "expected list type argument in unary operator");
+ ListRecTy *LType = dynamic_cast<ListRecTy*>(LHSt->getType());
+ if (LType == 0) {
+ TokError("expected list type argumnet in unary operator");
+ return 0;
+ }
+ if (Code == UnOpInit::CAR) {
+ Type = LType->getElementType();
+ }
+ else {
+ Type = LType;
+ }
+ }
+ }
+ }
+
if (Lex.getCode() != tgtok::r_paren) {
TokError("expected ')' in unary operator");
return 0;
@@ -1072,6 +1142,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec) {
break;
}
+ case tgtok::XCar:
+ case tgtok::XCdr:
+ case tgtok::XNull:
case tgtok::XCast: // Value ::= !unop '(' Value ')'
case tgtok::XConcat:
case tgtok::XSRA: