[lang][parser] better support for attributes

This commit is contained in:
Philippe Tillet
2019-08-22 21:02:38 -07:00
parent 845c0e5b93
commit 64a6910644
5 changed files with 101 additions and 58 deletions

View File

@@ -82,12 +82,12 @@ R"(
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
extern int get_program_id(int);
#define TN 128
#define TK 32
static const int TM = 128;
static const int TM __attribute__((one_of(128)));
static const int TN __attribute__((one_of(128)));
static const int TK __attribute__((one_of(32)));
void matmul(restrict )" + a_ty + R"( * A __attribute__((readonly, aligned(16))),
restrict )" + b_ty + R"( * B __attribute__((readonly, aligned(16))),

View File

@@ -54,6 +54,13 @@ class TranslationUnit;
*/
class ASTNode {
public:
struct Attr{
std::string name;
std::vector<Expr*> vals;
};
using AttrList = std::vector<Attr>;
public:
virtual ~ASTNode() {}
virtual void Accept(Visitor* v) = 0;
@@ -561,7 +568,7 @@ class Identifier: public Expr {
friend class LValAssigner;
public:
static Identifier* New(const Token* tok, QualType type, Linkage linkage);
static Identifier* New(const Token* tok, QualType type, Linkage linkage, const AttrList& attrList={});
virtual ~Identifier() {}
virtual void Accept(Visitor* v);
virtual bool IsLVal() { return false; }
@@ -583,11 +590,12 @@ public:
virtual void TypeChecking() {}
protected:
Identifier(const Token* tok, QualType type, enum Linkage linkage)
: Expr(tok, type), linkage_(linkage) {}
Identifier(const Token* tok, QualType type, enum Linkage linkage, const AttrList& attrList={})
: Expr(tok, type), linkage_(linkage), attrList_(attrList) {}
// An identifier has property linkage
enum Linkage linkage_;
AttrList attrList_;
};
@@ -624,13 +632,15 @@ public:
int storage=0,
enum Linkage linkage=L_NONE,
unsigned char bitFieldBegin=0,
unsigned char bitFieldWidth=0);
unsigned char bitFieldWidth=0,
const AttrList& attrList={});
static Object* NewAnony(const Token* tok,
QualType type,
int storage=0,
enum Linkage linkage=L_NONE,
unsigned char bitFieldBegin=0,
unsigned char bitFieldWidth=0);
unsigned char bitFieldWidth=0,
const AttrList& attrList={});
~Object() {}
virtual void Accept(Visitor* v);
virtual Object* ToObject() { return this; }
@@ -685,7 +695,8 @@ protected:
int storage=0,
enum Linkage linkage=L_NONE,
unsigned char bitFieldBegin=0,
unsigned char bitFieldWidth=0)
unsigned char bitFieldWidth=0,
const AttrList& attrList={})
: Identifier(tok, type, linkage),
storage_(storage),
offset_(0),
@@ -693,7 +704,8 @@ protected:
decl_(nullptr),
bitFieldBegin_(bitFieldBegin),
bitFieldWidth_(bitFieldWidth),
anonymous_(false) {}
anonymous_(false),
attrList_(attrList){}
private:
int storage_;
@@ -708,6 +720,8 @@ private:
bool anonymous_;
long id_ {0};
ASTNode::AttrList attrList_;
};

View File

@@ -14,7 +14,18 @@
class Preprocessor;
using TokenTypePair = std::pair<const Token*, QualType>;
struct DeclInfo {
DeclInfo(const Token* _tok,
QualType _type,
ASTNode::AttrList _attrs = {})
: tok(_tok), type(_type), attrs(_attrs) {}
const Token* tok;
QualType type;
ASTNode::AttrList attrs;
};
class Parser {
using LiteralList = std::vector<Constant*>;
@@ -103,7 +114,7 @@ public:
Type* ParseEnumerator(ArithmType* type);
int ParseQual();
QualType ParsePointer(QualType typePointedTo);
TokenTypePair ParseDeclarator(QualType type);
DeclInfo ParseDeclarator(QualType type);
QualType ParseArrayFuncDeclarator(const Token* ident, QualType base);
int ParseArrayLength();
TileType::ShapeInt ParseTileShape();
@@ -155,14 +166,14 @@ public:
CompoundStmt* ParseCaseStmt();
CompoundStmt* ParseDefaultStmt();
Identifier* ProcessDeclarator(const Token* tok,
QualType type,
QualType type, const ASTNode::AttrList &attrs,
int storageSpec,
int funcSpec,
int align);
// GNU extensions
void TryAttributeSpecList();
void ParseAttributeSpec();
void ParseAttribute();
ASTNode::AttrList TryAttributeSpecList();
void ParseAttributeSpec(ASTNode::AttrList &attrList);
ASTNode::Attr ParseAttribute();
bool IsTypeName(const Token* tok) const{
if (tok->IsTypeSpecQual())
return true;

View File

@@ -823,8 +823,9 @@ void FuncCall::TypeChecking() {
Identifier* Identifier::New(const Token* tok,
QualType type,
enum Linkage linkage) {
auto ret = new (identifierPool.Alloc()) Identifier(tok, type, linkage);
enum Linkage linkage,
const AttrList &attrList) {
auto ret = new (identifierPool.Alloc()) Identifier(tok, type, linkage, attrList);
ret->pool_ = &identifierPool;
return ret;
}
@@ -862,9 +863,10 @@ Object* Object::New(const Token* tok,
int storage,
enum Linkage linkage,
unsigned char bitFieldBegin,
unsigned char bitFieldWidth) {
unsigned char bitFieldWidth,
const AttrList& attrList) {
auto ret = new (objectPool.Alloc())
Object(tok, type, storage, linkage, bitFieldBegin, bitFieldWidth);
Object(tok, type, storage, linkage, bitFieldBegin, bitFieldWidth, attrList);
ret->pool_ = &objectPool;
static long id = 0;
@@ -879,9 +881,10 @@ Object* Object::NewAnony(const Token* tok,
int storage,
enum Linkage linkage,
unsigned char bitFieldBegin,
unsigned char bitFieldWidth) {
unsigned char bitFieldWidth,
const AttrList& attrList) {
auto ret = new (objectPool.Alloc())
Object(tok, type, storage, linkage, bitFieldBegin, bitFieldWidth);
Object(tok, type, storage, linkage, bitFieldBegin, bitFieldWidth, attrList);
ret->pool_ = &objectPool;
ret->anonymous_ = true;

View File

@@ -72,16 +72,18 @@ void Parser::ParseTranslationUnit() {
int storageSpec, funcSpec, align;
auto declType = ParseDeclSpec(&storageSpec, &funcSpec, &align);
auto tokTypePair = ParseDeclarator(declType);
auto tok = tokTypePair.first;
auto type = tokTypePair.second;
auto declInfo = ParseDeclarator(declType);
auto tok = declInfo.tok;
auto type = declInfo.type;
auto attrs = declInfo.attrs;
if (tok == nullptr) {
ts_.Expect(';');
continue;
}
auto ident = ProcessDeclarator(tok, type, storageSpec, funcSpec, align);
auto ident = ProcessDeclarator(tok, type, attrs, storageSpec, funcSpec, align);
type = ident->Type();
if (tok && type->ToFunc() && ts_.Try('{')) { // Function definition
@@ -1339,9 +1341,9 @@ StructType* Parser::ParseStructUnionDecl(StructType* type) {
int align;
auto baseType = ParseDeclSpec(nullptr, nullptr, &align);
do {
auto tokTypePair = ParseDeclarator(baseType);
auto tok = tokTypePair.first;
auto memberType = tokTypePair.second;
auto declInfo = ParseDeclarator(baseType);
auto tok = declInfo.tok;
auto memberType = declInfo.type;
if (ts_.Try(':')) {
ParseBitField(type, tok, memberType);
@@ -1505,15 +1507,15 @@ static QualType ModifyBase(QualType type, QualType base, QualType newBase) {
* if token is nullptr, then we are parsing abstract declarator
* else, parsing direct declarator.
*/
TokenTypePair Parser::ParseDeclarator(QualType base) {
DeclInfo Parser::ParseDeclarator(QualType base) {
// May be pointer
auto pointerType = ParsePointer(base);
if (ts_.Try('(')) {
// 现在的 pointerType 并不是正确的 base type
auto tokenTypePair = ParseDeclarator(pointerType);
auto tok = tokenTypePair.first;
auto type = tokenTypePair.second;
auto declInfo = ParseDeclarator(pointerType);
auto tok = declInfo.tok;
auto type = declInfo.type;
ts_.Expect(')');
@@ -1521,23 +1523,24 @@ TokenTypePair Parser::ParseDeclarator(QualType base) {
// 修正 base type
auto retType = ModifyBase(type, pointerType, newBase);
return TokenTypePair(tokenTypePair.first, retType);
return DeclInfo(declInfo.tok, retType);
} else if (ts_.Peek()->IsIdentifier()) {
auto tok = ts_.Next();
// GNU extension: variable attributes
TryAttributeSpecList();
ASTNode::AttrList attrList = TryAttributeSpecList();
auto retType = ParseArrayFuncDeclarator(tok, pointerType);
return TokenTypePair(tok, retType);
return DeclInfo(tok, retType, attrList);
} else {
errTok_ = ts_.Peek();
auto retType = ParseArrayFuncDeclarator(nullptr, pointerType);
return TokenTypePair(nullptr, retType);
return DeclInfo(nullptr, retType);
}
}
Identifier* Parser::ProcessDeclarator(const Token* tok,
QualType type,
const ASTNode::AttrList& attrs,
int storageSpec,
int funcSpec,
int align) {
@@ -1564,6 +1567,11 @@ Identifier* Parser::ProcessDeclarator(const Token* tok,
// TODO(wgtdkp): add previous declaration information
return ident;
}
if(!attrs.empty()) {
Error(tok, "typedef attributes not allowed");
}
ident = Identifier::New(tok, type, L_NONE);
curScope_->Insert(ident);
return ident;
@@ -1658,9 +1666,9 @@ Identifier* Parser::ProcessDeclarator(const Token* tok,
// C11 6.7.5 [2]: alignment specifier
if (align > 0)
Error(tok, "alignment specified for function");
ret = Identifier::New(tok, type, linkage);
ret = Identifier::New(tok, type, linkage, attrs);
} else {
auto obj = Object::New(tok, type, storageSpec, linkage);
auto obj = Object::New(tok, type, storageSpec, linkage, 0, 0, attrs);
if (align > 0)
obj->SetAlign(align);
ret = obj;
@@ -1797,14 +1805,15 @@ Object* Parser::ParseParamDecl() {
// C11 6.7.5 [2]: alignment specifier cannot be specified in params
auto type = ParseDeclSpec(&storageSpec, &funcSpec, nullptr);
auto tokTypePair = ParseDeclarator(type);
auto tok = tokTypePair.first;
type = Type::MayCast(tokTypePair.second, true);
auto tok = tokTypePair.tok;
type = Type::MayCast(tokTypePair.type, true);
auto attrs = tokTypePair.attrs;
if (!tok) { // Abstract declarator
return Object::NewAnony(ts_.Peek(), type, 0, Linkage::L_NONE);
}
// Align set to non positive, stands for not specified
auto ident = ProcessDeclarator(tok, type, storageSpec, funcSpec, -1);
auto ident = ProcessDeclarator(tok, type, attrs, storageSpec, funcSpec, -1);
if (!ident->ToObject())
Error(ident, "expect object in param list");
@@ -1813,9 +1822,9 @@ Object* Parser::ParseParamDecl() {
QualType Parser::ParseAbstractDeclarator(QualType type) {
auto tokenTypePair = ParseDeclarator(type);
auto tok = tokenTypePair.first;
type = tokenTypePair.second;
auto declInfo = ParseDeclarator(type);
auto tok = declInfo.tok;
type = declInfo.type;
if (tok) { // Not a abstract declarator!
Error(tok, "unexpected identifier '%s'", tok->str_.c_str());
}
@@ -1827,14 +1836,15 @@ Identifier* Parser::ParseDirectDeclarator(QualType type,
int storageSpec,
int funcSpec,
int align) {
auto tokenTypePair = ParseDeclarator(type);
auto tok = tokenTypePair.first;
type = tokenTypePair.second;
auto declInfo = ParseDeclarator(type);
auto tok = declInfo.tok;
type = declInfo.type;
auto attrs = declInfo.attrs;
if (tok == nullptr) {
Error(errTok_, "expect identifier or '('");
}
return ProcessDeclarator(tok, type, storageSpec, funcSpec, align);
return ProcessDeclarator(tok, type, attrs, storageSpec, funcSpec, align);
}
@@ -2654,18 +2664,20 @@ Identifier* Parser::GetBuiltin(const Token* tok) {
*/
// Attribute
void Parser::TryAttributeSpecList() {
ASTNode::AttrList Parser::TryAttributeSpecList() {
ASTNode::AttrList attrList;
while (ts_.Try(Token::ATTRIBUTE))
ParseAttributeSpec();
ParseAttributeSpec(attrList);
return attrList;
}
void Parser::ParseAttributeSpec() {
void Parser::ParseAttributeSpec(ASTNode::AttrList& attrList) {
ts_.Expect('(');
ts_.Expect('(');
while (!ts_.Try(')')) {
ParseAttribute();
attrList.push_back(ParseAttribute());
if (!ts_.Try(',')) {
ts_.Expect(')');
break;
@@ -2675,17 +2687,20 @@ void Parser::ParseAttributeSpec() {
}
void Parser::ParseAttribute() {
ASTNode::Attr Parser::ParseAttribute() {
ASTNode::Attr ret;
if (!ts_.Test(Token::IDENTIFIER))
return;
return ret;
auto tok = ts_.Next();
ret.name = tok->str_;
if (ts_.Try('(')) {
if (ts_.Try(')'))
return;
auto tok = ts_.Next();
return ret;
ret.vals.push_back(ParseExpr());
if (ts_.Test(',')) {
while (ts_.Try(',')) {}
}
ts_.Try(')');
}
return ret;
}