Files
triton/lib/lang/parser.cc

2797 lines
72 KiB
C++
Raw Normal View History

#include "triton/lang/parser.h"
#include "triton/lang/cpp.h"
#include "triton/lang/encoding.h"
#include "triton/lang/error.h"
#include "triton/lang/evaluator.h"
#include "triton/lang/scope.h"
#include "triton/lang/type.h"
#include <iostream>
#include <set>
#include <string>
#include <climits>
FuncType* Parser::vaStartType_ {nullptr};
FuncType* Parser::vaArgType_ {nullptr};
FuncDef* Parser::EnterFunc(Identifier* ident) {
curFunc_ = FuncDef::New(ident, LabelStmt::New());
return curFunc_;
}
void Parser::ExitFunc() {
// Resolve 那些待定的jump
// 如果有jump无法resolve也就是有未定义的label报错
for (auto iter = unresolvedJumps_.begin();
iter != unresolvedJumps_.end(); ++iter) {
auto label = iter->first;
auto labelStmt = FindLabel(label->str_);
if (labelStmt == nullptr) {
Error(label, "label '%s' used but not defined",
label->str_.c_str());
}
iter->second->SetLabel(labelStmt);
}
unresolvedJumps_.clear(); //清空未定的 jump 动作
curLabels_.clear(); //清空 label map
curFunc_ = nullptr;
}
void Parser::EnterBlock(FuncType* funcType) {
curScope_ = new Scope(curScope_, S_BLOCK);
if (funcType) {
// Merge elements in param scope into current block scope
for (auto param: funcType->Params())
curScope_->Insert(param);
}
}
void Parser::Parse() {
DefineBuiltins();
ParseTranslationUnit();
}
void Parser::ParseTranslationUnit() {
while (!ts_.Peek()->IsEOF()) {
if (ts_.Try(Token::STATIC_ASSERT)) {
ParseStaticAssert();
continue;
} else if (ts_.Try(';')) {
continue;
}
int storageSpec, funcSpec, align;
auto declType = ParseDeclSpec(&storageSpec, &funcSpec, &align);
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, attrs, storageSpec, funcSpec, align);
type = ident->Type();
if (tok && type->ToFunc() && ts_.Try('{')) { // Function definition
unit_->Add(ParseFuncDef(ident));
} else { // Declaration
auto decl = ParseInitDeclarator(ident);
if (decl) unit_->Add(decl);
while (ts_.Try(',')) {
auto ident = ParseDirectDeclarator(declType, storageSpec,
funcSpec, align);
decl = ParseInitDeclarator(ident);
if (decl) unit_->Add(decl);
}
// GNU extension: function/type/variable attributes
TryAttributeSpecList();
ts_.Expect(';');
}
}
}
FuncDef* Parser::ParseFuncDef(Identifier* ident) {
auto funcDef = EnterFunc(ident);
if (funcDef->FuncType()->Complete()) {
Error(ident, "redefinition of '%s'", funcDef->Name().c_str());
}
// TODO(wgtdkp): param checking
auto funcType = ident->Type()->ToFunc();
funcType->SetComplete(true);
for (auto param: funcType->Params()) {
if (param->Anonymous())
Error(param, "param name omitted");
}
funcDef->SetBody(ParseCompoundStmt(funcType));
ExitFunc();
return funcDef;
}
Expr* Parser::ParseExpr() {
return ParseCommaExpr();
}
Expr* Parser::ParseCommaExpr() {
auto lhs = ParseAssignExpr();
auto tok = ts_.Peek();
while (ts_.Try(',')) {
auto rhs = ParseAssignExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Peek();
}
return lhs;
}
Expr* Parser::ParsePrimaryExpr() {
if (ts_.Empty()) {
Error(ts_.Peek(), "premature end of input");
}
auto tok = ts_.Next();
if (tok->tag_ == '(') {
auto expr = ParseExpr();
ts_.Expect(')');
return expr;
}
if (tok->IsIdentifier()) {
auto ident = curScope_->Find(tok);
if (ident) return ident;
if (IsBuiltin(tok->str_)) return GetBuiltin(tok);
Error(tok, "undefined symbol '%s'", tok->str_.c_str());
} else if (tok->IsConstant()) {
return ParseConstant(tok);
} else if (tok->IsLiteral()) {
return ConcatLiterals(tok);
} else if (tok->tag_ == Token::GENERIC) {
return ParseGeneric();
}
Error(tok, "'%s' unexpected", tok->str_.c_str());
return nullptr; // Make compiler happy
}
static void ConvertLiteral(std::string& val, Encoding enc) {
switch (enc) {
case Encoding::NONE:
case Encoding::UTF8: break;
case Encoding::CHAR16: ConvertToUTF16(val); break;
case Encoding::CHAR32:
case Encoding::WCHAR: ConvertToUTF32(val); break;
}
}
Constant* Parser::ConcatLiterals(const Token* tok) {
auto val = new std::string;
auto enc = Scanner(tok).ScanLiteral(*val);
ConvertLiteral(*val, enc);
while (ts_.Test(Token::LITERAL)) {
auto nextTok = ts_.Next();
std::string nextVal;
auto nextEnc = Scanner(nextTok).ScanLiteral(nextVal);
ConvertLiteral(nextVal, nextEnc);
if (enc == Encoding::NONE) {
ConvertLiteral(*val, nextEnc);
enc = nextEnc;
}
if (nextEnc != Encoding::NONE && nextEnc != enc)
Error(nextTok, "cannot concat lietrals with different encodings");
*val += nextVal;
}
int tag = T_CHAR;
switch (enc) {
case Encoding::NONE:
case Encoding::UTF8:
tag = T_CHAR; val->append(1, '\0'); break;
case Encoding::CHAR16:
tag = T_UNSIGNED | T_SHORT; val->append(2, '\0'); break;
case Encoding::CHAR32:
case Encoding::WCHAR:
tag = T_UNSIGNED | T_INT; val->append(4, '\0'); break;
}
return Constant::New(tok, tag, val);
}
Encoding Parser::ParseLiteral(std::string& str, const Token* tok) {
return Scanner(tok).ScanLiteral(str);
}
Constant* Parser::ParseConstant(const Token* tok) {
assert(tok->IsConstant());
if (tok->tag_ == Token::I_CONSTANT) {
return ParseInteger(tok);
} else if (tok->tag_ == Token::C_CONSTANT) {
return ParseCharacter(tok);
} else {
return ParseFloat(tok);
}
}
Constant* Parser::ParseFloat(const Token* tok) {
const auto& str = tok->str_;
size_t end = 0;
double val = 0.0;
try {
val = stod(str, &end);
} catch (const std::out_of_range& oor) {
Error(tok, "float out of range");
}
int tag = T_DOUBLE;
if (str[end] == 'f' || str[end] == 'F') {
tag = T_FLOAT;
++end;
} else if (str[end] == 'l' || str[end] == 'L') {
tag = T_LONG | T_DOUBLE;
++end;
}
if (str[end] != 0)
Error(tok, "invalid suffix");
return Constant::New(tok, tag, val);
}
Constant* Parser::ParseCharacter(const Token* tok) {
int val;
auto enc = Scanner(tok).ScanCharacter(val);
int tag;
switch (enc) {
case Encoding::NONE:
val = (char)val;
tag = T_INT; break;
case Encoding::CHAR16:
val = (char16_t)val;
tag = T_UNSIGNED | T_SHORT; break;
case Encoding::WCHAR:
case Encoding::CHAR32: tag = T_UNSIGNED | T_INT; break;
default: assert(false);
}
return Constant::New(tok, tag, static_cast<long>(val));
}
Constant* Parser::ParseInteger(const Token* tok) {
const auto& str = tok->str_;
size_t end = 0;
long val = 0;
try {
val = stoull(str, &end, 0);
} catch (const std::out_of_range& oor) {
Error(tok, "integer out of range");
}
int tag = 0;
for (; str[end]; ++end) {
if (str[end] == 'u' || str[end] == 'U') {
if (tag & T_UNSIGNED)
Error(tok, "invalid suffix");
tag |= T_UNSIGNED;
} else {
if ((tag & T_LONG) || (tag & T_LLONG))
Error(tok, "invalid suffix");
if (str[end + 1] == 'l' || str[end + 1] =='L') {
tag |= T_LLONG;
++end;
} else {
tag |= T_LONG;
}
}
}
bool decimal = ('1' <= str[0] && str[0] <= '9');
if (decimal) {
switch (tag) {
case 0:
tag |= !(val & ~(long)INT_MAX) ? T_INT: T_LONG; break;
case T_UNSIGNED:
tag |= !(val & ~(long)UINT_MAX) ? T_INT: T_LONG; break;
case T_LONG: break;
case T_UNSIGNED | T_LONG: break;
}
} else {
switch (tag) {
case 0:
tag |= !(val & ~(long)INT_MAX) ? T_INT
: !(val & ~(long)UINT_MAX) ? T_UNSIGNED
: !(val & ~(long)LONG_MAX) ? T_LONG
: T_UNSIGNED | T_LONG; break;
case T_UNSIGNED:
tag |= !(val & ~(long)UINT_MAX) ? T_INT: T_LONG; break;
case T_LONG:
tag |= !(val & ~(long)LONG_MAX) ? 0: T_UNSIGNED; break;
case T_UNSIGNED | T_LONG:
break;
}
}
return Constant::New(tok, tag, val);
}
Expr* Parser::ParseGeneric() {
ts_.Expect('(');
auto controlExpr = ParseAssignExpr();
ts_.Expect(',');
Expr* selectedExpr = nullptr;
bool isDefault = false;
while (true) {
if (ts_.Try(Token::DEFAULT)) {
ts_.Expect(':');
auto defaultExpr = ParseAssignExpr();
if (!selectedExpr) {
selectedExpr = defaultExpr;
isDefault = true;
}
} else {
auto tok = ts_.Peek();
auto type = ParseTypeName();
ts_.Expect(':');
auto expr = ParseAssignExpr();
if (type->Compatible(*controlExpr->Type())) {
if (selectedExpr && !isDefault) {
Error(tok, "more than one generic association"
" are compatible with control expression");
}
selectedExpr = expr;
isDefault = false;
}
}
if (!ts_.Try(',')) {
ts_.Expect(')');
break;
}
}
if (!selectedExpr)
Error(ts_.Peek(), "no compatible generic association");
return selectedExpr;
}
QualType Parser::TryCompoundLiteral() {
auto mark = ts_.Mark();
if (ts_.Try('(') && IsTypeName(ts_.Peek())) {
auto type = ParseTypeName();
if (ts_.Try(')') && ts_.Test('{'))
return type;
}
ts_.ResetTo(mark);
return nullptr;
}
Expr* Parser::ParsePostfixExpr() {
if (ts_.Peek()->IsEOF()) {
Error(ts_.Peek(), "premature end of input");
}
auto type = TryCompoundLiteral();
if (type) {
auto anony = ParseCompoundLiteral(type);
return ParsePostfixExprTail(anony);
}
auto primExpr = ParsePrimaryExpr();
return ParsePostfixExprTail(primExpr);
}
Object* Parser::ParseCompoundLiteral(QualType type) {
auto linkage = curScope_->Type() == S_FILE ? L_INTERNAL: L_NONE;
auto anony = Object::NewAnony(ts_.Peek(), type, 0, linkage);
auto decl = ParseInitDeclaratorSub(anony);
// Just for generator to find the compound literal
if (curScope_->Type() == S_FILE) {
unit_->Add(decl);
} else {
curScope_->Insert(anony->Repr(), anony);
}
return anony;
}
// Return the constructed postfix expression
Expr* Parser::ParsePostfixExprTail(Expr* lhs) {
while (true) {
auto tok = ts_.Next();
switch (tok->tag_) {
case '[': lhs = ParseSubScripting(lhs); break;
case '(': lhs = ParseFuncCall(lhs); break;
case Token::PTR: lhs = UnaryOp::New(Token::DEREF, lhs);
// Fall through
case '.': lhs = ParseMemberRef(tok, '.', lhs); break;
case Token::INC:
case Token::DEC: lhs = ParsePostfixIncDec(tok, lhs); break;
default: ts_.PutBack(); return lhs;
}
}
}
Expr* Parser::ParseSubScripting(Expr* lhs) {
auto lhsTile = lhs->Type()->ToTile();
if(lhsTile == nullptr)
Error(lhs, "tile expected");
TileType::ShapeInt lhsShape = lhsTile->Shape();
QualType lhsQual = lhsTile->Derived();
// create ret shape
TileType::ShapeInt shape;
TileType::ShapeInt axVec;
size_t i = 0;
const Token* tok;
std::vector<std::pair<int, int>> redInfo;
do {
tok = ts_.Next();
switch(tok->tag_) {
case ':':
shape.push_back(lhsShape[i++]);
break;
case Token::NEWAXIS:
shape.push_back(1);
break;
case Token::ADD:
case Token::SUB:
case Token::MAX:
case Token::MIN:{
int info = UnaryOp::encodeRed(i, tok->tag_);
redInfo.push_back({i, info});
shape.push_back(lhsShape[i++]);
break;
}
case '^':{
Expr* expr = ParseConditionalExpr();
EnsureInteger(expr);
int ax = Evaluator<long>().Eval(expr);
axVec.push_back(ax);
if(ax < 0 || ax >= lhsShape.size())
Error(tok, "unknown axis %d in transposition", ax);
shape.push_back(lhsShape[ax]);
i++;
break;
}
default:
Error(tok, "Unexpected subscript symbol encountered at dimension %d", i);
break;
}
}while(ts_.Try(','));
ts_.Expect(']');
// transposition mode
std::set<int> axSet(axVec.begin(), axVec.end());
if(!axSet.empty()){
if(axSet.size()!=lhsShape.size())
Error(tok, "transposition must address all axes of input array");
return TransOp::New(axVec, lhs);
}
// broadcasting mode
if(lhsShape.size() > i)
Error(tok, "broadcasting not using all operand axes");
// create ret tile
Expr* res = lhs;
for(auto r: redInfo){
shape.erase(shape.begin() + r.first);
Type *retType;
if(shape.empty())
retType = lhsQual.GetPtr();
else
retType = TileType::New(shape, lhsQual);
res = UnaryOp::New(Token::REDUCE, res, retType, r.second);
}
if(!shape.empty()){
TileType *retType = TileType::New(shape, lhsQual);
res = UnaryOp::New(Token::CAST, res, retType);
}
return res;
}
BinaryOp* Parser::ParseMemberRef(const Token* tok, int op, Expr* lhs) {
auto memberName = ts_.Peek()->str_;
ts_.Expect(Token::IDENTIFIER);
auto structUnionType = lhs->Type()->ToStruct();
if (structUnionType == nullptr) {
Error(tok, "an struct/union expected");
}
auto rhs = structUnionType->GetMember(memberName);
if (rhs == nullptr) {
Error(tok, "'%s' is not a member of '%s'",
memberName.c_str(), "[obj]");
}
return BinaryOp::New(tok, op, lhs, rhs);
}
UnaryOp* Parser::ParsePostfixIncDec(const Token* tok, Expr* operand) {
auto op = tok->tag_ == Token::INC ?
Token::POSTFIX_INC: Token::POSTFIX_DEC;
return UnaryOp::New(op, operand);
}
FuncCall* Parser::ParseFuncCall(Expr* designator) {
FuncCall::ArgList args;
while (!ts_.Try(')')) {
args.push_back(Expr::MayCast(ParseAssignExpr()));
if (!ts_.Test(')'))
ts_.Expect(',');
}
return FuncCall::New(designator, args);
}
Expr* Parser::ParseUnaryExpr() {
auto tok = ts_.Next();
switch (tok->tag_) {
case Token::ALIGNOF: return ParseAlignof();
case Token::SIZEOF: return ParseSizeof();
case Token::INC: return ParsePrefixIncDec(tok);
case Token::DEC: return ParsePrefixIncDec(tok);
case Token::EXP: return ParseUnaryIntrinsicOp(tok, Token::EXP); //FIXME: merge into generic array functions
2020-11-17 01:26:53 -05:00
case Token::SQRTF: return ParseUnaryIntrinsicOp(tok, Token::SQRTF);
2020-11-03 15:50:11 -05:00
case Token::LOG: return ParseUnaryIntrinsicOp(tok, Token::LOG); //FIXME: merge into generic array functions
case '&': return ParseUnaryOp(tok, Token::ADDR);
case '*': return ParseDerefOp(tok);
case '+': return ParseUnaryOp(tok, Token::PLUS);
case '-': return ParseUnaryOp(tok, Token::MINUS);
case '~': return ParseUnaryOp(tok, '~');
case '!': return ParseUnaryOp(tok, '!');
case '^': {
auto operand = ParseCastExpr();
TileType::ShapeInt shape = operand->Type()->ToTile()->Shape();
TransOp::PermInt perm(shape.size());
for(int d = 0; d < shape.size(); d++)
perm[d] = d;
std::rotate(perm.begin(), perm.begin() + 1, perm.end());
return TransOp::New(perm, operand);
}
default:
ts_.PutBack();
return ParsePostfixExpr();
}
}
Constant* Parser::ParseSizeof() {
QualType type(nullptr);
auto tok = ts_.Next();
if (tok->tag_ == '(' && IsTypeName(ts_.Peek())) {
type = ParseTypeName();
ts_.Expect(')');
} else {
ts_.PutBack();
auto expr = ParseUnaryExpr();
type = expr->Type();
}
if (type->ToFunc() || type->ToVoid()) {
} else if (!type->Complete()) {
Error(tok, "sizeof(incomplete type)");
}
long val = type->Width();
return Constant::New(tok, T_UNSIGNED | T_LONG, val);
}
Constant* Parser::ParseAlignof() {
ts_.Expect('(');
auto tok = ts_.Peek();
auto type = ParseTypeName();
ts_.Expect(')');
long val = type->Align();
return Constant::New(tok, T_UNSIGNED| T_LONG, val);
}
UnaryOp* Parser::ParsePrefixIncDec(const Token* tok) {
assert(tok->tag_ == Token::INC || tok->tag_ == Token::DEC);
auto op = tok->tag_ == Token::INC ?
Token::PREFIX_INC: Token::PREFIX_DEC;
auto operand = ParseUnaryExpr();
return UnaryOp::New(op, operand);
}
UnaryOp* Parser::ParseUnaryIntrinsicOp(const Token* tok, int op) {
ts_.Expect('(');
auto operand = ParseExpr();
ts_.Expect(')');
return UnaryOp::New(op, operand);
}
UnaryOp* Parser::ParseUnaryOp(const Token* tok, int op) {
auto operand = ParseCastExpr();
return UnaryOp::New(op, operand);
}
Expr* Parser::ParseDerefOp(const Token* tok) {
Expr* pred = nullptr;
if(ts_.Try('?')){
ts_.Expect('(');
pred = ParseExpr();
ts_.Expect(')');
}
Expr* addr = ParseCastExpr();
if(pred)
return BinaryOp::New(tok, Token::MASKED_DEREF, pred, addr);
else
return UnaryOp::New(Token::DEREF, addr);
}
QualType Parser::ParseTypeName() {
auto type = ParseSpecQual();
if (ts_.Test('*') || ts_.Test('(') || ts_.Test('[')) // abstract-declarator FIRST set
return ParseAbstractDeclarator(type);
return type;
}
Expr* Parser::ParseCastExpr() {
auto tok = ts_.Next();
// bitcast
if (tok->tag_ == Token::BITCAST) {
ts_.Expect('<');
auto type = ParseTypeName();
ts_.Expect('>');
ts_.Expect('(');
auto operand = ParseExpr();
ts_.Expect(')');
return UnaryOp::New(Token::BITCAST, operand, type);
}
// semantic cast
if (tok->tag_ == '(' && IsTypeName(ts_.Peek())) {
auto type = ParseTypeName();
ts_.Expect(')');
if (ts_.Test('{')) {
auto anony = ParseCompoundLiteral(type);
return ParsePostfixExprTail(anony);
}
auto operand = ParseCastExpr();
return UnaryOp::New(Token::CAST, operand, type);
}
ts_.PutBack();
return ParseUnaryExpr();
}
Expr* Parser::ParseRangeExpr() {
auto lhs = ParseCastExpr();
auto tok = ts_.Next();
while (tok->tag_ == Token::ELLIPSIS) {
auto rhs = ParseCastExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseMatmulExpr() {
auto lhs = ParseRangeExpr();
auto tok = ts_.Next();
while (tok->tag_ == Token::MATMUL) {
auto rhs = ParseRangeExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseMultiplicativeExpr() {
auto lhs = ParseMatmulExpr();
auto tok = ts_.Next();
while (tok->tag_ == '*' || tok->tag_ == '/' || tok->tag_ == '%') {
auto rhs = ParseMatmulExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseAdditiveExpr() {
auto lhs = ParseMultiplicativeExpr();
auto tok = ts_.Next();
while (tok->tag_ == '+' || tok->tag_ == '-') {
auto rhs = ParseMultiplicativeExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseShiftExpr() {
auto lhs = ParseAdditiveExpr();
auto tok = ts_.Next();
while (tok->tag_ == Token::LEFT || tok->tag_ == Token::RIGHT) {
auto rhs = ParseAdditiveExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseRelationalExpr() {
auto lhs = ParseShiftExpr();
auto tok = ts_.Next();
while (tok->tag_ == Token::LE || tok->tag_ == Token::GE
|| tok->tag_ == '<' || tok->tag_ == '>') {
auto rhs = ParseShiftExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseEqualityExpr() {
auto lhs = ParseRelationalExpr();
auto tok = ts_.Next();
while (tok->tag_ == Token::EQ || tok->tag_ == Token::NE) {
auto rhs = ParseRelationalExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Next();
}
ts_.PutBack();
return lhs;
}
Expr* Parser::ParseBitiwiseAndExpr() {
auto lhs = ParseEqualityExpr();
auto tok = ts_.Peek();
while (ts_.Try('&')) {
auto rhs = ParseEqualityExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Peek();
}
return lhs;
}
Expr* Parser::ParseBitwiseXorExpr() {
auto lhs = ParseBitiwiseAndExpr();
auto tok = ts_.Peek();
while (ts_.Try('^')) {
auto rhs = ParseBitiwiseAndExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Peek();
}
return lhs;
}
Expr* Parser::ParseBitwiseOrExpr() {
auto lhs = ParseBitwiseXorExpr();
auto tok = ts_.Peek();
while (ts_.Try('|')) {
auto rhs = ParseBitwiseXorExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Peek();
}
return lhs;
}
Expr* Parser::ParseLogicalAndExpr() {
auto lhs = ParseBitwiseOrExpr();
auto tok = ts_.Peek();
while (ts_.Try(Token::LOGICAL_AND)) {
auto rhs = ParseBitwiseOrExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Peek();
}
return lhs;
}
Expr* Parser::ParseLogicalOrExpr() {
auto lhs = ParseLogicalAndExpr();
auto tok = ts_.Peek();
while (ts_.Try(Token::LOGICAL_OR)) {
auto rhs = ParseLogicalAndExpr();
lhs = BinaryOp::New(tok, lhs, rhs);
tok = ts_.Peek();
}
return lhs;
}
Expr* Parser::ParseConditionalExpr() {
auto cond = ParseLogicalOrExpr();
auto tok = ts_.Peek();
if (ts_.Try('?')) {
// Non-standard GNU extension
// a ?: b equals a ? a: c
auto exprTrue = ts_.Test(':') ? cond: ParseExpr();
ts_.Expect(':');
auto exprFalse = ParseConditionalExpr();
return ConditionalOp::New(tok, cond, exprTrue, exprFalse);
}
return cond;
}
Expr* Parser::ParseAssignExpr() {
// Yes, I know the lhs should be unary expression,
// let it handled by type checking
Expr* lhs = ParseConditionalExpr();
Expr* rhs;
auto tok = ts_.Next();
switch (tok->tag_) {
case Token::MUL_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '*', lhs, rhs);
break;
case Token::DIV_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '/', lhs, rhs);
break;
case Token::MOD_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '%', lhs, rhs);
break;
case Token::ADD_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '+', lhs, rhs);
break;
case Token::SUB_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '-', lhs, rhs);
break;
case Token::LEFT_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, Token::LEFT, lhs, rhs);
break;
case Token::RIGHT_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, Token::RIGHT, lhs, rhs);
break;
case Token::AND_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '&', lhs, rhs);
break;
case Token::XOR_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '^', lhs, rhs);
break;
case Token::OR_ASSIGN:
rhs = ParseAssignExpr();
rhs = BinaryOp::New(tok, '|', lhs, rhs);
break;
case '=':
rhs = ParseAssignExpr();
break;
default:
ts_.PutBack();
return lhs; // Could be constant
}
return BinaryOp::New(tok, '=', lhs, rhs);
}
void Parser::ParseStaticAssert() {
ts_.Expect('(');
auto condExpr = ParseAssignExpr();
ts_.Expect(',');
auto msg = ConcatLiterals(ts_.Expect(Token::LITERAL));
ts_.Expect(')');
ts_.Expect(';');
if (!Evaluator<long>().Eval(condExpr)) {
Error(ts_.Peek(), "static assertion failed: %s\n",
msg->SVal()->c_str());
}
}
// Return: list of declarations
CompoundStmt* Parser::ParseDecl() {
StmtList stmts;
if (ts_.Try(Token::STATIC_ASSERT)) {
ParseStaticAssert();
} else {
int storageSpec, funcSpec, align;
auto type = ParseDeclSpec(&storageSpec, &funcSpec, &align);
if (!ts_.Test(';')) {
do {
auto ident = ParseDirectDeclarator(type, storageSpec, funcSpec, align);
auto init = ParseInitDeclarator(ident);
if (init) stmts.push_back(init);
} while (ts_.Try(','));
}
ts_.Expect(';');
}
return CompoundStmt::New(stmts);
}
// For state machine
enum {
// Compatibility for these key words
COMP_SIGNED = T_SHORT | T_INT | T_LONG | T_LLONG,
COMP_UNSIGNED = T_SHORT | T_INT | T_LONG | T_LLONG,
COMP_CHAR = T_SIGNED | T_UNSIGNED,
COMP_SHORT = T_SIGNED | T_UNSIGNED | T_INT,
COMP_INT = T_SIGNED | T_UNSIGNED | T_LONG | T_SHORT | T_LLONG,
COMP_LONG = T_SIGNED | T_UNSIGNED | T_LONG | T_INT,
COMP_DOUBLE = T_LONG | T_COMPLEX,
COMP_COMPLEX = T_FLOAT | T_DOUBLE | T_LONG,
COMP_THREAD = S_EXTERN | S_STATIC,
};
static inline void TypeLL(int& typeSpec) {
if (typeSpec & T_LONG) {
typeSpec &= ~T_LONG;
typeSpec |= T_LLONG;
} else {
typeSpec |= T_LONG;
}
}
QualType Parser::ParseSpecQual() {
return ParseDeclSpec(nullptr, nullptr, nullptr);
}
static void EnsureAndSetStorageSpec(const Token* tok, int* storage, int spec) {
if (!storage)
Error(tok, "unexpected storage specifier");
if (*storage != 0)
Error(tok, "duplicated storage specifier");
*storage |= spec;
}
/*
* param: storage: null, only type specifier and qualifier accepted;
*/
QualType Parser::ParseDeclSpec(int* storageSpec, int* funcSpec, int* alignSpec) {
#define ERR_FUNC_SPEC ("unexpected function specifier")
#define ERR_STOR_SPEC ("unexpected storage specifier")
#define ERR_DECL_SPEC ("two or more data types in declaration specifiers")
QualType type(nullptr);
int qualSpec = 0;
int typeSpec = 0;
if (storageSpec) *storageSpec = 0;
if (funcSpec) *funcSpec = 0;
if (alignSpec) *alignSpec = 0;
const Token* tok;
for (; ;) {
tok = ts_.Next();
switch (tok->tag_) {
// Function specifier
case Token::INLINE:
if (!funcSpec)
Error(tok, ERR_FUNC_SPEC);
*funcSpec |= F_INLINE;
break;
case Token::NORETURN:
if (!funcSpec)
Error(tok, ERR_FUNC_SPEC);
*funcSpec |= F_NORETURN;
break;
// Alignment specifier
case Token::ALIGNAS: {
if (!alignSpec)
Error(tok, "unexpected alignment specifier");
auto align = ParseAlignas();
if (align)
*alignSpec = align;
break;
}
// Storage specifier
// TODO(wgtdkp): typedef needs more constraints
case Token::TYPEDEF:
EnsureAndSetStorageSpec(tok, storageSpec, S_TYPEDEF);
break;
case Token::EXTERN:
EnsureAndSetStorageSpec(tok, storageSpec, S_EXTERN);
break;
case Token::GLOBAL:
EnsureAndSetStorageSpec(tok, storageSpec, S_GLOBAL);
break;
case Token::STATIC:
if (!storageSpec)
Error(tok, ERR_FUNC_SPEC);
if (*storageSpec & ~S_THREAD)
Error(tok, "duplicated storage specifier");
*storageSpec |= S_STATIC;
break;
case Token::THREAD:
if (!storageSpec)
Error(tok, ERR_FUNC_SPEC);
if (*storageSpec & ~COMP_THREAD)
Error(tok, "duplicated storage specifier");
*storageSpec |= S_THREAD;
break;
// Type qualifier
case Token::CONST: qualSpec |= Qualifier::CONST; break;
case Token::RESTRICT: qualSpec |= Qualifier::RESTRICT; break;
case Token::VOLATILE: qualSpec |= Qualifier::VOLATILE; break;
case Token::CMEM: qualSpec |= Qualifier::CMEM; break;
// Type specifier
case Token::SIGNED:
if (typeSpec & ~COMP_SIGNED)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_SIGNED;
break;
case Token::UNSIGNED:
if (typeSpec & ~COMP_UNSIGNED)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_UNSIGNED;
break;
case Token::VOID:
if (typeSpec & ~0)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_VOID;
break;
case Token::CHAR:
if (typeSpec & ~COMP_CHAR)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_CHAR;
break;
case Token::SHORT:
if (typeSpec & ~COMP_SHORT)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_SHORT;
break;
case Token::INT:
if (typeSpec & ~COMP_INT)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_INT;
break;
case Token::LONG:
if (typeSpec & ~COMP_LONG)
Error(tok, ERR_DECL_SPEC);
TypeLL(typeSpec);
break;
case Token::HALF:
if(typeSpec & ~T_COMPLEX)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_HALF;
break;
case Token::FLOAT:
if (typeSpec & ~T_COMPLEX)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_FLOAT;
break;
case Token::DOUBLE:
if (typeSpec & ~COMP_DOUBLE)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_DOUBLE;
break;
case Token::BOOL:
if (typeSpec != 0)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_BOOL;
break;
case Token::COMPLEX:
if (typeSpec & ~COMP_COMPLEX)
Error(tok, ERR_DECL_SPEC);
typeSpec |= T_COMPLEX;
break;
case Token::STRUCT:
case Token::UNION:
if (typeSpec & ~0)
Error(tok, ERR_DECL_SPEC);
type = ParseStructUnionSpec(Token::STRUCT == tok->tag_);
typeSpec |= T_STRUCT_UNION;
break;
case Token::ENUM:
if (typeSpec != 0)
Error(tok, ERR_DECL_SPEC);
type = ParseEnumSpec();
typeSpec |= T_ENUM;
break;
case Token::ATOMIC:
Error(tok, "atomic not supported");
break;
default:
if (typeSpec == 0 && IsTypeName(tok)) {
auto ident = curScope_->Find(tok);
type = ident->Type();
// We may change the length of a array type by initializer,
// thus, make a copy of this type.
auto arrType = type->ToArray();
if (arrType && !type->Complete())
type = ArrayType::New(arrType->Len(), arrType->Derived());
typeSpec |= T_TYPEDEF_NAME;
} else {
goto end_of_loop;
}
}
}
end_of_loop:
ts_.PutBack();
switch (typeSpec) {
case 0:
Error(tok, "expect type specifier");
break;
case T_VOID:
type = VoidType::New();
break;
case T_STRUCT_UNION:
case T_ENUM:
case T_TYPEDEF_NAME:
break;
default:
type = ArithmType::New(typeSpec);
break;
}
// GNU extension: type attributes
//if (storageSpec && (*storageSpec & S_TYPEDEF))
// TryAttributeSpecList();
return QualType(type.GetPtr(), qualSpec | type.Qual());
#undef ERR_FUNC_SPEC
#undef ERR_STOR_SPEC
#undef ERR_DECL_SPEC
}
int Parser::ParseAlignas() {
int align;
ts_.Expect('(');
auto tok = ts_.Peek();
if (IsTypeName(ts_.Peek())) {
auto type = ParseTypeName();
ts_.Expect(')');
align = type->Align();
} else {
auto expr = ParseExpr();
align = Evaluator<long>().Eval(expr);
ts_.Expect(')');
}
if (align < 0 || ((align - 1) & align))
Error(tok, "requested alignment is not a positive power of 2");
return align;
}
Type* Parser::ParseEnumSpec() {
// GNU extension: type attributes
TryAttributeSpecList();
std::string tagName;
auto tok = ts_.Peek();
if (ts_.Try(Token::IDENTIFIER)) {
tagName = tok->str_;
if (ts_.Try('{')) {
// 定义enum类型
auto tagIdent = curScope_->FindTagInCurScope(tok);
if (!tagIdent) {
auto type = ArithmType::New(T_INT);
auto ident = Identifier::New(tok, type, L_NONE);
curScope_->InsertTag(ident);
return ParseEnumerator(type); // 处理反大括号: '}'
}
if (!tagIdent->Type()->IsInteger()) // struct/union tag
Error(tok, "redefinition of enumeration tag '%s'", tagName.c_str());
return ParseEnumerator(tagIdent->Type()->ToArithm());
} else {
auto tagIdent = curScope_->FindTag(tok);
if (tagIdent) {
return tagIdent->Type();
}
auto type = ArithmType::New(T_INT);
auto ident = Identifier::New(tok, type, L_NONE);
curScope_->InsertTag(ident);
return type;
}
}
ts_.Expect('{');
auto type = ArithmType::New(T_INT);
return ParseEnumerator(type); // 处理反大括号: '}'
}
Type* Parser::ParseEnumerator(ArithmType* type) {
assert(type && type->IsInteger());
int val = 0;
do {
auto tok = ts_.Expect(Token::IDENTIFIER);
// GNU extension: enumerator attributes
TryAttributeSpecList();
const auto& enumName = tok->str_;
auto ident = curScope_->FindInCurScope(tok);
if (ident) {
Error(tok, "redefinition of enumerator '%s'", enumName.c_str());
}
if (ts_.Try('=')) {
auto expr = ParseAssignExpr();
val = Evaluator<long>().Eval(expr);
}
auto enumer = Enumerator::New(tok, val);
++val;
curScope_->Insert(enumer);
ts_.Try(',');
} while (!ts_.Try('}'));
type->SetComplete(true);
return type;
}
/*
* name space
* 1.label, goto end;
* 2.struct/union/enum tag
* 3.struct/union
* 4.
*/
Type* Parser::ParseStructUnionSpec(bool isStruct) {
// GNU extension: type attributes
TryAttributeSpecList();
std::string tagName;
auto tok = ts_.Peek();
if (ts_.Try(Token::IDENTIFIER)) {
tagName = tok->str_;
if (ts_.Try('{')) {
// 看见大括号表明现在将定义该struct/union类型
// 我们不用关心上层scope是否定义了此tag如果定义了那么就直接覆盖定义
auto tagIdent = curScope_->FindTagInCurScope(tok);
if (!tagIdent) {
// 现在是在当前scope第一次看到name所以现在是第一次定义连前向声明都没有
auto type = StructType::New(isStruct, tagName.size(), curScope_);
auto ident = Identifier::New(tok, type, L_NONE);
curScope_->InsertTag(ident);
return ParseStructUnionDecl(type); // 处理反大括号: '}'
}
// 在当前scope找到了类型但可能只是声明注意声明与定义只能出现在同一个scope
// 1.如果声明在定义的外层scope,那么即使在内层scope定义了完整的类型此声明仍然是无效的
// 因为如论如何编译器都不会在内部scope里面去找定义所以声明的类型仍然是不完整的
// 2.如果声明在定义的内层scope,(也就是先定义再在内部scope声明),这时,不完整的声明会覆盖掉完整的定义;
// 因为编译器总是向上查找符号,不管找到的是完整的还是不完整的,都要;
if (!tagIdent->Type()->Complete()) {
// 找到了此tag的前向声明并更新其符号表最后设置为complete type
return ParseStructUnionDecl(tagIdent->Type()->ToStruct());
} else {
// 在当前作用域找到了完整的定义,并且现在正在定义同名的类型,所以报错;
Error(tok, "redefinition of struct tag '%s'", tagName.c_str());
}
} else {
// 没有大括号表明不是定义一个struct/union;那么现在只可能是在:
// 1.声明;
// 2.声明的同时,定义指针(指针允许指向不完整类型) (struct Foo* p; 是合法的) 或者其他合法的类型;
// 如果现在索引符号表,那么:
// 1.可能找到name的完整定义也可能只找得到不完整的声明不管name指示的是不是完整类型我们都只能选择name指示的类型
// 2.如果我们在符号表里面压根找不到name,那么现在是name的第一次声明创建不完整的类型并插入符号表
auto tagIdent = curScope_->FindTag(tok);
// 如果tag已经定义或声明那么直接返回此定义或者声明
if (tagIdent) {
return tagIdent->Type();
}
// 如果tag尚没有定义或者声明那么创建此tag的声明(因为没有见到‘{’,所以不会是定义)
auto type = StructType::New(isStruct, true, curScope_);
// 因为有tag所以不是匿名的struct/union 向当前的scope插入此tag
auto ident = Identifier::New(tok, type, L_NONE);
curScope_->InsertTag(ident);
return type;
}
}
// 没见到identifier那就必须有struct/union的定义这叫做匿名struct/union;
ts_.Expect('{');
// 现在如果是有tag那它没有前向声明如果是没有tag那更加没有前向声明
// 所以现在是第一次开始定义一个完整的struct/union类型
auto type = StructType::New(isStruct, tagName.size(), curScope_);
return ParseStructUnionDecl(type); // 处理反大括号: '}'
}
StructType* Parser::ParseStructUnionDecl(StructType* type) {
#define ADD_MEMBER() { \
auto member = Object::New(tok, memberType); \
if (align > 0) \
member->SetAlign(align); \
type->AddMember(member); \
}
// 既然是定义,那输入肯定是不完整类型,不然就是重定义了
assert(type && !type->Complete());
auto scopeBackup = curScope_;
curScope_ = type->MemberMap(); // Internal symbol lookup rely on curScope_
while (!ts_.Try('}')) {
if (ts_.Empty()) {
Error(ts_.Peek(), "premature end of input");
}
if(ts_.Try(Token::STATIC_ASSERT)) {
ParseStaticAssert();
continue;
}
// 解析type specifier/qualifier, 不接受storage等
int align;
auto baseType = ParseDeclSpec(nullptr, nullptr, &align);
do {
auto declInfo = ParseDeclarator(baseType);
auto tok = declInfo.tok;
auto memberType = declInfo.type;
if (ts_.Try(':')) {
ParseBitField(type, tok, memberType);
continue;
}
if (tok == nullptr) {
auto suType = memberType->ToStruct();
if (suType && !suType->HasTag()) {
auto anony = Object::NewAnony(ts_.Peek(), suType);
type->MergeAnony(anony);
continue;
} else {
Error(ts_.Peek(), "declaration does not declare anything");
}
}
const auto& name = tok->str_;
if (type->GetMember(name)) {
Error(tok, "duplicate member '%s'", name.c_str());
} else if (!memberType->Complete()) {
// C11 6.7.2.1 [3]:
if (type->IsStruct() &&
// Struct has more than one named member
type->MemberMap()->size() > 0 &&
memberType->ToArray()) {
ts_.Expect(';'); ts_.Expect('}');
ADD_MEMBER();
goto finalize;
} else {
Error(tok, "field '%s' has incomplete type", name.c_str());
}
} else if (memberType->ToFunc()) {
Error(tok, "field '%s' declared as a function", name.c_str());
}
ADD_MEMBER();
} while (ts_.Try(','));
ts_.Expect(';');
}
finalize:
// GNU extension: type attributes
TryAttributeSpecList();
// struct/union定义结束设置其为完整类型
type->Finalize();
type->SetComplete(true);
// TODO(wgtdkp): we need to export tags defined inside struct
const auto& tags = curScope_->AllTagsInCurScope();
for (auto tag: tags) {
if (scopeBackup->FindTag(tag->Tok()))
Error(tag, "redefinition of tag '%s'\n", tag->Name().c_str());
scopeBackup->InsertTag(tag);
}
curScope_ = scopeBackup;
return type;
}
void Parser::ParseBitField(StructType* structType,
const Token* tok,
QualType type) {
if (!type->IsInteger()) {
Error(tok ? tok: ts_.Peek(), "expect integer type for bitfield");
}
auto expr = ParseAssignExpr();
auto width = Evaluator<long>().Eval(expr);
if (width < 0) {
Error(expr, "expect non negative value");
} else if (width == 0 && tok) {
Error(tok, "no declarator expected for a bitfield with width 0");
} else if (width > type->Width() * 8) {
Error(expr, "width exceeds its type");
}
auto offset = structType->Offset() - type->Width();
// C11 6.7.5 [2]: alignment attribute shall not be specified in declaration of a bit field
// so here is ok to use type->Align()
offset = Type::MakeAlign(std::max(offset, 0), type->Align());
int bitFieldOffset;
unsigned char begin;
if (!structType->IsStruct()) {
begin = 0;
bitFieldOffset = 0;
} else if (structType->Members().size() == 0) {
begin = 0;
bitFieldOffset = 0;
} else {
auto last = structType->Members().back();
auto totalBits = last->Offset() * 8;
if (last->BitFieldWidth()) {
totalBits += last->BitFieldEnd();
} else { // Is not bit field
totalBits += last->Type()->Width() * 8;
}
if (width == 0)
width = type->Width() * 8 - totalBits; // So posterior bitfield would be packed
if (width == 0) // A bitfield with zero width is never added to member list
return; // Because we use bitfield width to tell if a member is bitfield or not.
if (width + totalBits <= type->Width() * 8) {
begin = totalBits % 8;
bitFieldOffset = totalBits / 8;
} else {
begin = 0;
bitFieldOffset = Type::MakeAlign(structType->Offset(), type->Width());
}
}
Object* bitField;
if (tok) {
bitField = Object::New(tok, type, 0, L_NONE, begin, width);
} else {
bitField = Object::NewAnony(ts_.Peek(), type, 0, L_NONE, begin, width);
}
structType->AddBitField(bitField, bitFieldOffset);
}
int Parser::ParseQual() {
int qualSpec = 0;
for (; ;) {
auto tok = ts_.Next();
switch (tok->tag_) {
case Token::CONST: qualSpec |= Qualifier::CONST; break;
case Token::RESTRICT: qualSpec |= Qualifier::RESTRICT; break;
case Token::VOLATILE: qualSpec |= Qualifier::VOLATILE; break;
case Token::CMEM: qualSpec |= Qualifier::CMEM; break;
case Token::ATOMIC: Error(tok, "do not support 'atomic'"); break;
default: ts_.PutBack(); return qualSpec;
}
}
}
QualType Parser::ParsePointer(QualType typePointedTo) {
while (ts_.Try('*')) {
auto t = PointerType::New(typePointedTo);
typePointedTo = QualType(t, ParseQual());
}
return typePointedTo;
}
static QualType ModifyBase(QualType type, QualType base, QualType newBase) {
if (type == base)
return newBase;
auto ty = type->ToDerived();
ty->SetDerived(ModifyBase(ty->Derived(), base, newBase));
return ty;
}
/*
* Return: pair of token(must be identifier) and it's type
* if token is nullptr, then we are parsing abstract declarator
* else, parsing direct declarator.
*/
DeclInfo Parser::ParseDeclarator(QualType base) {
// May be pointer
auto pointerType = ParsePointer(base);
if (ts_.Try('(')) {
// 现在的 pointerType 并不是正确的 base type
auto declInfo = ParseDeclarator(pointerType);
auto tok = declInfo.tok;
auto type = declInfo.type;
ts_.Expect(')');
auto newBase = ParseArrayFuncDeclarator(tok, pointerType);
// 修正 base type
auto retType = ModifyBase(type, pointerType, newBase);
return DeclInfo(declInfo.tok, retType);
} else if (ts_.Peek()->IsIdentifier()) {
auto tok = ts_.Next();
// GNU extension: variable attributes
ASTNode::AttrList attrList = TryAttributeSpecList();
auto retType = ParseArrayFuncDeclarator(tok, pointerType);
return DeclInfo(tok, retType, attrList);
} else {
errTok_ = ts_.Peek();
auto retType = ParseArrayFuncDeclarator(nullptr, pointerType);
return DeclInfo(nullptr, retType);
}
}
Identifier* Parser::ProcessDeclarator(const Token* tok,
QualType type,
const ASTNode::AttrList& attrs,
int storageSpec,
int funcSpec,
int align) {
assert(tok);
// 检查在同一 scope 是否已经定义此变量
// 如果 storage 是 typedef那么应该往符号表里面插入 type
// 定义 void 类型变量是非法的只能是指向void类型的指针
// 如果 funcSpec != 0, 那么现在必须是在定义函数,否则出错
const auto& name = tok->str_;
Identifier* ident;
if (storageSpec & S_TYPEDEF) {
// C11 6.7.5 [2]: alignment specifier
if (align > 0)
Error(tok, "alignment specified for typedef");
ident = curScope_->FindInCurScope(tok);
if (ident) { // There is prio declaration in the same scope
// The same declaration, simply return the prio declaration
if (!type->Compatible(*ident->Type()))
Error(tok, "conflicting types for '%s'", name.c_str());
// 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;
}
if (type->ToVoid()) {
Error(tok, "variable or field '%s' declared void",
name.c_str());
}
if (type->ToFunc() && curScope_->Type() != S_FILE
&& (storageSpec & S_STATIC)) {
Error(tok, "invalid storage class for function '%s'", name.c_str());
}
Linkage linkage;
// Identifiers in function prototype have no linkage
if (curScope_->Type() == S_PROTO) {
linkage = L_NONE;
} else if (curScope_->Type() == S_FILE) {
linkage = L_EXTERNAL; // Default linkage for file scope identifiers
if (storageSpec & S_STATIC)
linkage = L_INTERNAL;
} else if (!(storageSpec & S_EXTERN)) {
linkage = L_NONE; // Default linkage for block scope identifiers
if (type->ToFunc())
linkage = L_EXTERNAL;
} else {
linkage = L_EXTERNAL;
}
ident = curScope_->FindInCurScope(tok);
if (ident) { // There is prio declaration in the same scope
if (!type->Compatible(*ident->Type())) {
Error(tok, "conflicting types for '%s'", name.c_str());
}
// The same scope prio declaration has no linkage,
// there is a redeclaration error
if (linkage == L_NONE) {
Error(tok, "redeclaration of '%s' with no linkage",
name.c_str());
} else if (linkage == L_EXTERNAL) {
if (ident->Linkage() == L_NONE) {
Error(tok, "conflicting linkage for '%s'", name.c_str());
}
} else {
if (ident->Linkage() != L_INTERNAL) {
Error(tok, "conflicting linkage for '%s'", name.c_str());
}
}
// The same declaration, simply return the prio declaration
if (!ident->Type()->Complete())
ident->Type()->SetComplete(type->Complete());
// Prio declaration of a function may omit the param name
if (type->ToFunc())
ident->Type()->ToFunc()->SetParams(type->ToFunc()->Params());
else if (ident->ToObject() && !(storageSpec & S_EXTERN))
ident->ToObject()->SetStorage(ident->ToObject()->Storage() & ~S_EXTERN);
return ident;
} else if (linkage == L_EXTERNAL) {
ident = curScope_->Find(tok);
if (ident) {
if (!type->Compatible(*ident->Type())) {
Error(tok, "conflicting types for '%s'", name.c_str());
}
if (ident->Linkage() != L_NONE) {
linkage = ident->Linkage();
}
// Don't return, override it
} else {
ident = externalSymbols_->FindInCurScope(tok);
if (ident) {
if (!type->Compatible(*ident->Type())) {
Error(tok, "conflicting types for '%s'", name.c_str());
}
// TODO(wgtdkp): ???????
// Don't return
// To stop later declaration with the same name in the same scope overriding this declaration
// Useless here, just keep it
if (!ident->Type()->Complete())
ident->Type()->SetComplete(type->Complete());
//return ident;
}
}
}
Identifier* ret;
// TODO(wgtdkp): Treat function as object ?
if (type->ToFunc()) {
// C11 6.7.5 [2]: alignment specifier
if (align > 0)
Error(tok, "alignment specified for function");
ret = Identifier::New(tok, type, linkage, attrs);
} else {
auto obj = Object::New(tok, type, storageSpec, linkage, 0, 0, attrs);
if (align > 0)
obj->SetAlign(align);
ret = obj;
}
curScope_->Insert(ret);
if (linkage == L_EXTERNAL && ident == nullptr) {
externalSymbols_->Insert(ret);
}
return ret;
}
QualType Parser::ParseArrayFuncDeclarator(const Token* ident, QualType base) {
if (ts_.Try('[')) {
if(!base->IsScalar()) {
Error(ts_.Peek(), "tiles must have scalar elements");
}
auto shape = ParseTileShape();
ts_.Expect(']');
base = ParseArrayFuncDeclarator(ident, base);
if (!base->Complete()) {
Error(ident, "'%s' has incomplete element type", ident->str_.c_str());
}
// return a pointer for tiles in constant memory:
return TileType::New(shape, base);
} else if (ts_.Try('(')) { // Function declaration
if (base->ToFunc()) {
Error(ts_.Peek(),
"the return value of function cannot be function");
} else if (nullptr != base->ToArray()) {
Error(ts_.Peek(),
"the return value of function cannot be array");
}
FuncType::ParamList params;
EnterProto();
auto variadic = ParseParamList(params);
ExitProto();
ts_.Expect(')');
base = ParseArrayFuncDeclarator(ident, base);
return FuncType::New(base, 0, variadic, params);
}
return base;
}
/*
* Return: -1, length not specified
*/
int Parser::ParseArrayLength() {
auto hasStatic = ts_.Try(Token::STATIC);
auto qual = ParseQual();
if (0 != qual)
hasStatic = ts_.Try(Token::STATIC);
// 不支持变长数组
if (!hasStatic && ts_.Test(']'))
return -1;
auto expr = ParseAssignExpr();
EnsureInteger(expr);
auto ret = Evaluator<long>().Eval(expr);
if (ret < 0) {
Error(expr, "size of array is negative");
}
return ret;
}
TileType::ShapeInt Parser::ParseTileShape() {
TileType::ShapeInt ret;
size_t i = 0;
do {
Expr* expr = ParseConditionalExpr();
EnsureInteger(expr);
int dim = Evaluator<long>().Eval(expr);
if (dim < 0)
Error(expr, "shape %d of tile is negative", i);
ret.push_back(dim);
i++;
}while(ts_.Try(','));
return ret;
}
/*
* Return: true, variadic;
*/
bool Parser::ParseParamList(FuncType::ParamList& params) {
if (ts_.Test(')'))
return false;
auto param = ParseParamDecl();
if (param->Type()->ToVoid())
return false;
params.push_back(param);
while (ts_.Try(',')) {
if (ts_.Try(Token::ELLIPSIS))
return true;
param = ParseParamDecl();
if (param->Type()->ToVoid())
Error(param, "'void' must be the only parameter");
params.push_back(param);
}
return false;
}
Object* Parser::ParseParamDecl() {
int storageSpec, funcSpec;
// 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.tok;
QualType fullType(tokTypePair.type.GetPtr(), type.Qual());
type = Type::MayCast(fullType, 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, attrs, storageSpec, funcSpec, -1);
if (!ident->ToObject())
Error(ident, "expect object in param list");
return ident->ToObject();
}
QualType Parser::ParseAbstractDeclarator(QualType type) {
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());
}
return type;
}
Identifier* Parser::ParseDirectDeclarator(QualType type,
int storageSpec,
int funcSpec,
int align) {
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, attrs, storageSpec, funcSpec, align);
}
Declaration* Parser::ParseInitDeclarator(Identifier* ident) {
auto obj = ident->ToObject();
if (!obj) { // Do not record function Declaration
return nullptr;
}
const auto& name = obj->Name();
if (ts_.Try('=')) {
return ParseInitDeclaratorSub(obj);
}
if (!obj->Type()->Complete()) {
if (obj->Linkage() == L_NONE) {
Error(obj, "storage size of '%s' isnt known", name.c_str());
}
// FIXME(wgtdkp):
// Discards the incomplete object declarations
// It causes linking failure of forward-declared objects with imcomplete type
return nullptr;
}
if (!obj->Decl()) {
auto decl = Declaration::New(obj);
obj->SetDecl(decl);
return decl;
}
return nullptr;
}
Declaration* Parser::ParseInitDeclaratorSub(Object* obj) {
const auto& name = obj->Name();
if ((curScope_->Type() != S_FILE) && obj->Linkage() != L_NONE) {
Error(obj, "'%s' has both 'extern' and initializer", name.c_str());
}
if (!obj->Type()->Complete() && !obj->Type()->ToArray()) {
Error(obj, "variable '%s' has initializer but incomplete type",
name.c_str());
}
if (obj->HasInit()) {
Error(obj, "redefinition of variable '%s'", name.c_str());
}
// There could be more than one declaration for
// an object in the same scope.
// But it must has external or internal linkage.
// So, for external/internal objects,
// the initialization will always go to
// the first declaration. As the initialization
// is evaluated at compile time,
// the order doesn't matter.
// For objects with no linkage, there is
// always only one declaration.
// Once again, we need not to worry about
// the order of the initialization.
if (obj->Decl()) {
ParseInitializer(obj->Decl(), obj->Type(), 0, false, true);
return nullptr;
} else {
auto decl = Declaration::New(obj);
ParseInitializer(decl, obj->Type(), 0, false, true);
obj->SetDecl(decl);
return decl;
}
}
void Parser::ParseInitializer(Declaration* decl,
QualType type,
int offset,
bool designated,
bool forceBrace,
unsigned char bitFieldBegin,
unsigned char bitFieldWidth) {
if (designated && !ts_.Test('.') && !ts_.Test('[')) {
ts_.Expect('=');
}
// std::cout << "parsing initialized " << decl->Obj()->Name() << std::endl;
Expr* expr;
auto arrType = type->ToArray();
auto structType = type->ToStruct();
// A compound literal in initializer is reduced to a initializer directly
// It means that the compound literal will never be created
//auto literalType = TryCompoundLiteral();
//if (literalType && !literalType->Compatible(*type))
// Error("incompatible type of initializer");
if (arrType) {
if (forceBrace && !ts_.Test('{') && !ts_.Test(Token::LITERAL)) {
ts_.Expect('{');
} else if (!ParseLiteralInitializer(decl, arrType, offset)) {
ParseArrayInitializer(decl, arrType, offset, designated);
arrType->SetComplete(true);
}
return;
} else if (structType) {
if (!ts_.Test('.') && !ts_.Test('{')) {
auto mark = ts_.Mark();
expr = ParseAssignExpr();
if (structType->Compatible(*expr->Type())) {
decl->AddInit({structType, offset, expr});
return;
}
ts_.ResetTo(mark);
if (forceBrace)
ts_.Expect('{');
}
return ParseStructInitializer(decl, structType, offset, designated);
}
// Scalar type
auto hasBrace = ts_.Try('{');
expr = ParseAssignExpr();
if (hasBrace) {
ts_.Try(',');
ts_.Expect('}');
}
decl->AddInit({type.GetPtr(), offset, expr, bitFieldBegin, bitFieldWidth});
}
bool Parser::ParseLiteralInitializer(Declaration* decl,
ArrayType* type,
int offset) {
if (!type->Derived()->IsInteger())
return false;
auto hasBrace = ts_.Try('{');
if (!ts_.Test(Token::LITERAL)) {
if (hasBrace) ts_.PutBack();
return false;
}
auto literal = ConcatLiterals(ts_.Next());
auto tok = literal->Tok();
if (hasBrace) {
ts_.Try(',');
ts_.Expect('}');
}
if (!type->Complete()) {
type->SetLen(literal->Type()->ToArray()->Len());
type->SetComplete(true);
}
auto width = std::min(type->Width(), literal->Type()->Width());
auto str = literal->SVal()->c_str();
for (; width >= 8; width -= 8) {
auto p = reinterpret_cast<const long*>(str);
auto type = ArithmType::New(T_LONG);
auto val = Constant::New(tok, T_LONG, static_cast<long>(*p));
decl->AddInit({type, offset, val});
offset += 8;
str += 8;
}
for (; width >= 4; width -= 4) {
auto p = reinterpret_cast<const int*>(str);
auto type = ArithmType::New(T_INT);
auto val = Constant::New(tok, T_INT, static_cast<long>(*p));
decl->AddInit({type, offset, val});
offset += 4;
str += 4;
}
for (; width >= 2; width -= 2) {
auto p = reinterpret_cast<const short*>(str);
auto type = ArithmType::New(T_SHORT);
auto val = Constant::New(tok, T_SHORT, static_cast<long>(*p));
decl->AddInit({type, offset, val});
offset += 2;
str += 2;
}
for (; width >= 1; --width) {
auto p = str;
auto type = ArithmType::New(T_CHAR);
auto val = Constant::New(tok, T_CHAR, static_cast<long>(*p));
decl->AddInit({type, offset, val});
offset++;
str++;
}
return true;
}
void Parser::ParseArrayInitializer(Declaration* decl,
ArrayType* type,
int offset,
bool designated) {
assert(type);
if (!type->Complete())
type->SetLen(0);
int idx = 0;
auto width = type->Derived()->Width();
auto hasBrace = ts_.Try('{');
while (true) {
if (ts_.Test('}')) {
if (hasBrace)
ts_.Next();
return;
}
if (!designated && !hasBrace && (ts_.Test('.') || ts_.Test('['))) {
ts_.PutBack(); // Put the read comma(',') back
return;
} else if ((designated = ts_.Try('['))) {
auto expr = ParseAssignExpr();
EnsureInteger(expr);
idx = Evaluator<long>().Eval(expr);
ts_.Expect(']');
if (idx < 0 || (type->Complete() && idx >= type->Len())) {
Error(ts_.Peek(), "excess elements in array initializer");
}
}
ParseInitializer(decl, type->Derived(), offset + idx * width, designated);
designated = false;
++idx;
if (type->Complete() && idx >= type->Len()) {
break;
} else if (!type->Complete()) {
type->SetLen(std::max(idx, type->Len()));
}
// Needless comma at the end is legal
if (!ts_.Try(',')) {
if (hasBrace)
ts_.Expect('}');
return;
}
}
if (hasBrace) {
ts_.Try(',');
if (!ts_.Try('}')) {
Error(ts_.Peek(), "excess elements in array initializer");
}
}
}
StructType::Iterator Parser::ParseStructDesignator(StructType* type,
const std::string& name) {
auto iter = type->Members().begin();
for (; iter != type->Members().end(); ++iter) {
if ((*iter)->Anonymous()) {
auto anonyType = (*iter)->Type()->ToStruct();
assert(anonyType);
if (anonyType->GetMember(name)) {
return iter; // ParseStructDesignator(anonyType);
}
} else if ((*iter)->Name() == name) {
return iter;
}
}
assert(false);
return iter;
}
void Parser::ParseStructInitializer(Declaration* decl,
StructType* type,
int offset,
bool designated) {
assert(type);
auto hasBrace = ts_.Try('{');
auto member = type->Members().begin();
while (true) {
if (ts_.Test('}')) {
if (hasBrace)
ts_.Next();
return;
}
if (!designated && !hasBrace && (ts_.Test('.') || ts_.Test('['))) {
ts_.PutBack(); // Put the read comma(',') back
return;
}
if ((designated = ts_.Try('.'))) {
auto tok = ts_.Expect(Token::IDENTIFIER);
const auto& name = tok->str_;
if (!type->GetMember(name)) {
Error(tok, "member '%s' not found", name.c_str());
}
member = ParseStructDesignator(type, name);
}
if (member == type->Members().end())
break;
if ((*member)->Anonymous()) {
if (designated) { // Put back '.' and member name.
ts_.PutBack();
ts_.PutBack();
}
// Because offsets of member of anonymous struct/union are based
// directly on external struct/union
ParseInitializer(decl, (*member)->Type(), offset, designated, false,
(*member)->BitFieldBegin(), (*member)->BitFieldWidth());
} else {
ParseInitializer(decl, (*member)->Type(),
offset + (*member)->Offset(), designated, false,
(*member)->BitFieldBegin(), (*member)->BitFieldWidth());
}
designated = false;
++member;
// Union, just init the first member
if (!type->IsStruct())
break;
if (!hasBrace && member == type->Members().end())
break;
// Needless comma at the end is allowed
if (!ts_.Try(',')) {
if (hasBrace)
ts_.Expect('}');
return;
}
}
if (hasBrace) {
ts_.Try(',');
if (!ts_.Try('}')) {
Error(ts_.Peek(), "excess members in struct initializer");
}
}
}
/*
* Statements
*/
Stmt* Parser::ParseStmt() {
auto tok = ts_.Next();
if (tok->IsEOF())
Error(tok, "premature end of input");
switch (tok->tag_) {
// GNU extension: statement attributes
case Token::ATTRIBUTE:
TryAttributeSpecList();
case ';':
return EmptyStmt::New();
case '{':
return ParseCompoundStmt();
case Token::IF:
return ParseIfStmt();
case Token::SWITCH:
return ParseSwitchStmt();
case Token::WHILE:
return ParseWhileStmt();
case Token::DO:
return ParseDoStmt();
case Token::FOR:
return ParseForStmt();
case Token::GOTO:
return ParseGotoStmt();
case Token::CONTINUE:
return ParseContinueStmt();
case Token::BREAK:
return ParseBreakStmt();
case Token::RETURN:
return ParseReturnStmt();
case Token::CASE:
return ParseCaseStmt();
case Token::DEFAULT:
return ParseDefaultStmt();
}
if (tok->IsIdentifier() && ts_.Try(':')) {
// GNU extension: label attributes
TryAttributeSpecList();
return ParseLabelStmt(tok);
}
ts_.PutBack();
auto expr = ParseExpr();
ts_.Expect(';');
return expr;
}
CompoundStmt* Parser::ParseCompoundStmt(FuncType* funcType) {
EnterBlock(funcType);
std::list<Stmt*> stmts;
while (!ts_.Try('}')) {
if (ts_.Peek()->IsEOF()) {
Error(ts_.Peek(), "premature end of input");
}
if (IsType(ts_.Peek())) {
stmts.push_back(ParseDecl());
} else {
stmts.push_back(ParseStmt());
}
}
auto scope = curScope_;
ExitBlock();
return CompoundStmt::New(stmts, scope);
}
IfStmt* Parser::ParseIfStmt() {
ts_.Expect('(');
auto tok = ts_.Peek();
auto cond = ParseExpr();
if (!cond->Type()->IsScalar()) {
Error(tok, "expect scalar");
}
ts_.Expect(')');
auto then = ParseStmt();
Stmt* els = nullptr;
if (ts_.Try(Token::ELSE))
els = ParseStmt();
return IfStmt::New(cond, then, els);
}
/*
* for
* for (declaration; expression1; expression2) statement
*
* declaration
* cond: if (expression1) then empty
* else goto end
* statement
* step: expression2
* goto cond
* next:
*/
#define ENTER_LOOP_BODY(breakDest, continueDest) \
{ \
LabelStmt* breakDestBackup = breakDest_; \
LabelStmt* continueDestBackup = continueDest_; \
breakDest_ = breakDest; \
continueDest_ = continueDest;
#define EXIT_LOOP_BODY() \
breakDest_ = breakDestBackup; \
continueDest_ = continueDestBackup; \
}
ForStmt* Parser::ParseForStmt() {
EnterBlock();
ts_.Expect('(');
// init
Stmt* init = nullptr;
if (IsType(ts_.Peek())) {
init = ParseDecl();
} else if (!ts_.Try(';')) {
init = ParseExpr();
ts_.Expect(';');
}
// cond
Expr* cond = nullptr;
if (!ts_.Try(';')) {
cond = ParseExpr();
ts_.Expect(';');
}
// step
Expr* step = nullptr;
if (!ts_.Try(')')) {
step = ParseExpr();
ts_.Expect(')');
}
// body
Stmt* body = ParseStmt();
ExitBlock();
return ForStmt::New(body, init, cond, step);
}
/*
* while
* while (expression) statement
*
* cond: if (expression) then empty
* else goto end
* statement
* goto cond
* end:
*/
CompoundStmt* Parser::ParseWhileStmt() {
std::list<Stmt*> stmts;
ts_.Expect('(');
auto tok = ts_.Peek();
auto condExpr = ParseExpr();
ts_.Expect(')');
if (!condExpr->Type()->IsScalar()) {
Error(tok, "scalar expression expected");
}
auto condLabel = LabelStmt::New();
auto endLabel = LabelStmt::New();
auto gotoEndStmt = JumpStmt::New(endLabel);
auto ifStmt = IfStmt::New(condExpr, EmptyStmt::New(), gotoEndStmt);
stmts.push_back(condLabel);
stmts.push_back(ifStmt);
Stmt* bodyStmt;
ENTER_LOOP_BODY(endLabel, condLabel)
bodyStmt = ParseStmt();
EXIT_LOOP_BODY()
stmts.push_back(bodyStmt);
stmts.push_back(JumpStmt::New(condLabel));
stmts.push_back(endLabel);
return CompoundStmt::New(stmts);
}
/*
* do-while
* do statement while (expression)
*
* begin: statement
* cond: if (expression) then goto begin
* else goto end
* end:
*/
CompoundStmt* Parser::ParseDoStmt() {
auto beginLabel = LabelStmt::New();
auto condLabel = LabelStmt::New();
auto endLabel = LabelStmt::New();
Stmt* bodyStmt;
ENTER_LOOP_BODY(endLabel, beginLabel)
bodyStmt = ParseStmt();
EXIT_LOOP_BODY()
ts_.Expect(Token::WHILE);
ts_.Expect('(');
auto condExpr = ParseExpr();
ts_.Expect(')');
ts_.Expect(';');
auto gotoBeginStmt = JumpStmt::New(beginLabel);
auto gotoEndStmt = JumpStmt::New(endLabel);
auto ifStmt = IfStmt::New(condExpr, gotoBeginStmt, gotoEndStmt);
std::list<Stmt*> stmts;
stmts.push_back(beginLabel);
stmts.push_back(bodyStmt);
stmts.push_back(condLabel);
stmts.push_back(ifStmt);
stmts.push_back(endLabel);
return CompoundStmt::New(stmts);
}
#undef ENTER_LOOP_BODY
#undef EXIT_LOOP_BODY
#define ENTER_SWITCH_BODY(breakDest, caseLabels) \
{ \
CaseLabelList* caseLabelsBackup = caseLabels_; \
LabelStmt* defaultLabelBackup = defaultLabel_; \
LabelStmt* breakDestBackup = breakDest_; \
breakDest_ = breakDest; \
caseLabels_ = &caseLabels; \
defaultLabel_ = nullptr;
#define EXIT_SWITCH_BODY() \
caseLabels_ = caseLabelsBackup; \
breakDest_ = breakDestBackup; \
defaultLabel_ = defaultLabelBackup; \
}
/*
* switch
* jump stmt (skip case labels)
* case labels
* jump stmts
* default jump stmt
*/
CompoundStmt* Parser::ParseSwitchStmt() {
std::list<Stmt*> stmts;
ts_.Expect('(');
auto tok = ts_.Peek();
auto expr = ParseExpr();
ts_.Expect(')');
if (!expr->Type()->IsInteger()) {
Error(tok, "switch quantity not an integer");
}
auto testLabel = LabelStmt::New();
auto endLabel = LabelStmt::New();
auto t = TempVar::New(expr->Type());
auto assign = BinaryOp::New(tok, '=', t, expr);
stmts.push_back(assign);
stmts.push_back(JumpStmt::New(testLabel));
CaseLabelList caseLabels;
ENTER_SWITCH_BODY(endLabel, caseLabels);
auto bodyStmt = ParseStmt(); // Fill caseLabels and defaultLabel
stmts.push_back(bodyStmt);
stmts.push_back(JumpStmt::New(endLabel));
stmts.push_back(testLabel);
for (auto iter = caseLabels.begin();
iter != caseLabels.end(); ++iter) {
auto cond = BinaryOp::New(tok, Token::EQ, t, iter->first);
auto then = JumpStmt::New(iter->second);
auto ifStmt = IfStmt::New(cond, then, nullptr);
stmts.push_back(ifStmt);
}
if (defaultLabel_)
stmts.push_back(JumpStmt::New(defaultLabel_));
EXIT_SWITCH_BODY();
stmts.push_back(endLabel);
return CompoundStmt::New(stmts);
}
#undef ENTER_SWITCH_BODY
#undef EXIT_SWITCH_BODY
CompoundStmt* Parser::ParseCaseStmt() {
auto tok = ts_.Peek();
// Case ranges: Non-standard GNU extension
long begin, end;
begin = Evaluator<long>().Eval(ParseAssignExpr());
if (ts_.Try(Token::ELLIPSIS))
end = Evaluator<long>().Eval(ParseAssignExpr());
else
end = begin;
ts_.Expect(':');
auto labelStmt = LabelStmt::New();
for (auto val = begin; val <= end; ++val) {
if (val > INT_MAX)
Error(tok, "case range exceed range of int");
auto cons = Constant::New(tok, T_INT, val);
caseLabels_->push_back(std::make_pair(cons, labelStmt));
}
std::list<Stmt*> stmts;
stmts.push_back(labelStmt);
stmts.push_back(ParseStmt());
return CompoundStmt::New(stmts);
}
CompoundStmt* Parser::ParseDefaultStmt() {
auto tok = ts_.Peek();
ts_.Expect(':');
if (defaultLabel_) { // There is a 'default' stmt
Error(tok, "multiple default labels in one switch");
}
auto labelStmt = LabelStmt::New();
defaultLabel_ = labelStmt;
std::list<Stmt*> stmts;
stmts.push_back(labelStmt);
stmts.push_back(ParseStmt());
return CompoundStmt::New(stmts);
}
JumpStmt* Parser::ParseContinueStmt() {
auto tok = ts_.Peek();
ts_.Expect(';');
if (continueDest_ == nullptr) {
Error(tok, "'continue' is allowed only in loop");
}
return JumpStmt::New(continueDest_);
}
JumpStmt* Parser::ParseBreakStmt() {
auto tok = ts_.Peek();
ts_.Expect(';');
if (breakDest_ == nullptr) {
Error(tok, "'break' is allowed only in switch/loop");
}
return JumpStmt::New(breakDest_);
}
ReturnStmt* Parser::ParseReturnStmt() {
Expr* expr;
if (ts_.Try(';')) {
expr = nullptr;
} else {
expr = ParseExpr();
ts_.Expect(';');
auto retType = curFunc_->FuncType()->Derived();
expr = Expr::MayCast(expr, retType);
}
return ReturnStmt::New(expr);
}
JumpStmt* Parser::ParseGotoStmt() {
auto label = ts_.Peek();
ts_.Expect(Token::IDENTIFIER);
ts_.Expect(';');
auto labelStmt = FindLabel(label->str_);
if (labelStmt) {
return JumpStmt::New(labelStmt);
}
auto unresolvedJump = JumpStmt::New(nullptr);
unresolvedJumps_.push_back(std::make_pair(label, unresolvedJump));
return unresolvedJump;
}
CompoundStmt* Parser::ParseLabelStmt(const Token* label) {
const auto& labelStr = label->str_;
auto stmt = ParseStmt();
if (nullptr != FindLabel(labelStr)) {
Error(label, "redefinition of label '%s'", labelStr.c_str());
}
auto labelStmt = LabelStmt::New();
AddLabel(labelStr, labelStmt);
std::list<Stmt*> stmts;
stmts.push_back(labelStmt);
stmts.push_back(stmt);
return CompoundStmt::New(stmts);
}
bool Parser::IsBuiltin(const std::string& name) {
return name == "__builtin_va_arg" ||
name == "__builtin_va_start";
}
bool Parser::IsBuiltin(FuncType* type) {
assert(vaStartType_ && vaArgType_);
return type == vaStartType_ || type == vaArgType_;
}
// Builtin functions will be inlined
void Parser::DefineBuiltins() {
// FIXME: potential bug: using same object for params!!!
auto voidPtr = PointerType::New(VoidType::New());
auto param = Object::New(nullptr, voidPtr);
FuncType::ParamList pl;
pl.push_back(param);
pl.push_back(param);
vaStartType_ = FuncType::New(VoidType::New(), F_INLINE, false, pl);
vaArgType_ = FuncType::New(voidPtr, F_INLINE, false, pl);
}
Identifier* Parser::GetBuiltin(const Token* tok) {
assert(vaStartType_ && vaArgType_);
static Identifier* vaStart = nullptr;
static Identifier* vaArg = nullptr;
const auto& name = tok->str_;
if (name == "__builtin_va_start") {
if (!vaStart)
vaStart = Identifier::New(tok, vaStartType_, Linkage::L_EXTERNAL);
return vaStart;
} else if (name == "__builtin_va_arg") {
if (!vaArg)
vaArg = Identifier::New(tok, vaArgType_, Linkage::L_EXTERNAL);
return vaArg;
}
assert(false);
return nullptr;
}
/*
* GNU extensions
*/
// Attribute
ASTNode::AttrList Parser::TryAttributeSpecList() {
ASTNode::AttrList attrList;
while (ts_.Try(Token::ATTRIBUTE))
ParseAttributeSpec(attrList);
return attrList;
}
void Parser::ParseAttributeSpec(ASTNode::AttrList& attrList) {
ts_.Expect('(');
ts_.Expect('(');
while (!ts_.Try(')')) {
attrList.push_back(ParseAttribute());
if (!ts_.Try(',')) {
ts_.Expect(')');
break;
}
}
ts_.Expect(')');
}
ASTNode::Attr Parser::ParseAttribute() {
ASTNode::Attr ret;
if (!ts_.Test(Token::IDENTIFIER))
return ret;
auto tok = ts_.Next();
std::string name = tok->str_;
// set kind
if(name == "aligned")
ret.kind = ASTNode::Attr::ALIGNED;
else if(name == "readonly")
ret.kind = ASTNode::Attr::READONLY;
else if(name == "writeonly")
ret.kind = ASTNode::Attr::WRITEONLY;
else if(name == "multipleof")
ret.kind = ASTNode::Attr::MULTIPLEOF;
else if(name == "noalias")
ret.kind = ASTNode::Attr::NOALIAS;
else if(name == "retune")
ret.kind = ASTNode::Attr::RETUNE;
else
Error(tok, "unknown attribute kind");
// set exprs
if (ts_.Try('(')) {
if (ts_.Try(')'))
return ret;
ret.vals.push_back(ParseExpr());
if (ts_.Test(',')) {
while (ts_.Try(',')) {}
}
ts_.Try(')');
}
return ret;
}