Preliminary struct and union support.
Working features: - struct - union - nested structs - anonymous structs - forward declarations - '.' and '->' - copying structs using '=' Missing features: - passing structs by value - returning structs by value - typedef - sizeof Example: struct v {float x, y, z, w; }; void add(struct v* result, struct v* a, struct v* b) { result->x = a->x + b->x; result->y = a->y + b->y; result->z = a->z + b->z; result->w = a->w + b->w; } Reworked size-of and alignment logic to support structs. Improved encoding of ARM immediate constants.
This commit is contained in:
parent
c0f253359f
commit
9221bcccb3
480
libacc/acc.cpp
480
libacc/acc.cpp
|
@ -157,9 +157,11 @@ class Compiler : public ErrorSink {
|
|||
|
||||
struct Type {
|
||||
TypeTag tag;
|
||||
tokenid_t id; // For function arguments, local vars
|
||||
int length; // length of array
|
||||
Type* pHead;
|
||||
tokenid_t id; // For function arguments, global vars, local vars, struct elements
|
||||
tokenid_t structTag; // For structs the name of the struct
|
||||
int length; // length of array, offset of struct element. -1 means struct is forward defined
|
||||
int alignment; // for structs only
|
||||
Type* pHead; // For a struct this is the prototype struct.
|
||||
Type* pTail;
|
||||
};
|
||||
|
||||
|
@ -341,6 +343,9 @@ class Compiler : public ErrorSink {
|
|||
/* Load floating point value from global address. */
|
||||
virtual void loadFloat(int address, Type* pType) = 0;
|
||||
|
||||
/* Add the struct offset in bytes to R0, change the type to pType */
|
||||
virtual void addStructOffsetR0(int offset, Type* pType) = 0;
|
||||
|
||||
/* Jump to a target, and return the address of the word that
|
||||
* holds the target data, in case it needs to be fixed up later.
|
||||
*/
|
||||
|
@ -508,16 +513,6 @@ class Compiler : public ErrorSink {
|
|||
*/
|
||||
virtual size_t sizeOf(Type* type) = 0;
|
||||
|
||||
/**
|
||||
* Stack alignment of this type of data
|
||||
*/
|
||||
virtual size_t stackAlignmentOf(Type* pType) = 0;
|
||||
|
||||
/**
|
||||
* Argument stack argument size of this data type.
|
||||
*/
|
||||
virtual size_t stackSizeOf(Type* pType) = 0;
|
||||
|
||||
virtual Type* getR0Type() {
|
||||
return mExpressionStack.back().pType;
|
||||
}
|
||||
|
@ -675,7 +670,6 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Type* mkpInt;
|
||||
|
||||
private:
|
||||
|
@ -801,6 +795,19 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void addStructOffsetR0(int offset, Type* pType) {
|
||||
if (offset) {
|
||||
size_t immediate = 0;
|
||||
if (encode12BitImmediate(offset, &immediate)) {
|
||||
o4(0xE2800000 | immediate); // add r0, r0, #offset
|
||||
} else {
|
||||
error("structure offset out of range: %d", offset);
|
||||
}
|
||||
}
|
||||
setR0Type(pType, ET_LVALUE);
|
||||
}
|
||||
|
||||
virtual int gjmp(int t) {
|
||||
return o4(0xEA000000 | encodeAddress(t)); // b .L33
|
||||
}
|
||||
|
@ -1367,6 +1374,15 @@ class Compiler : public ErrorSink {
|
|||
o4(0xE1C200F0); // strd r0, [r2]
|
||||
#endif
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
{
|
||||
int size = sizeOf(pDestType);
|
||||
if (size > 0) {
|
||||
liReg(size, 1);
|
||||
callRuntime((void*) runtime_structCopy);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("storeR0ToTOS: unimplemented type %d",
|
||||
pDestType->tag);
|
||||
|
@ -1407,6 +1423,8 @@ class Compiler : public ErrorSink {
|
|||
case TY_ARRAY:
|
||||
pNewType = pNewType->pTail;
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
break;
|
||||
default:
|
||||
error("loadR0FromR0: unimplemented type %d", tag);
|
||||
break;
|
||||
|
@ -1417,13 +1435,18 @@ class Compiler : public ErrorSink {
|
|||
virtual void leaR0(int ea, Type* pPointerType, ExpressionType et) {
|
||||
if (ea > -LOCAL && ea < LOCAL) {
|
||||
// Local, fp relative
|
||||
if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) {
|
||||
error("Offset out of range: %08x", ea);
|
||||
}
|
||||
|
||||
size_t immediate = 0;
|
||||
bool inRange = false;
|
||||
if (ea < 0) {
|
||||
o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea
|
||||
inRange = encode12BitImmediate(-ea, &immediate);
|
||||
o4(0xE24B0000 | immediate); // sub r0, fp, #ea
|
||||
} else {
|
||||
o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea
|
||||
inRange = encode12BitImmediate(ea, &immediate);
|
||||
o4(0xE28B0000 | immediate); // add r0, fp, #ea
|
||||
}
|
||||
if (! inRange) {
|
||||
error("Offset out of range: %08x", ea);
|
||||
}
|
||||
} else {
|
||||
// Global, absolute.
|
||||
|
@ -1750,9 +1773,16 @@ class Compiler : public ErrorSink {
|
|||
case TY_CHAR:
|
||||
return 1;
|
||||
case TY_SHORT:
|
||||
return 1;
|
||||
return 2;
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_ARRAY:
|
||||
return alignmentOf(pType->pHead);
|
||||
case TY_STRUCT:
|
||||
return pType->pHead->alignment & 0x7fffffff;
|
||||
case TY_FUNC:
|
||||
error("alignment of func not supported");
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
|
@ -1777,37 +1807,14 @@ class Compiler : public ErrorSink {
|
|||
return 4;
|
||||
case TY_ARRAY:
|
||||
return pType->length * sizeOf(pType->pHead);
|
||||
case TY_STRUCT:
|
||||
return pType->pHead->length;
|
||||
default:
|
||||
error("Unsupported type %d", pType->tag);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t stackAlignmentOf(Type* pType) {
|
||||
switch(pType->tag) {
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_ARRAY:
|
||||
return stackAlignmentOf(pType->pHead);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t stackSizeOf(Type* pType) {
|
||||
switch(pType->tag) {
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_ARRAY:
|
||||
return sizeOf(pType);
|
||||
case TY_FUNC:
|
||||
error("stackSizeOf func not supported");
|
||||
return 4;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static FILE* disasmOut;
|
||||
|
||||
|
@ -1986,19 +1993,42 @@ class Compiler : public ErrorSink {
|
|||
void liReg(int t, int reg) {
|
||||
assert(reg >= 0 && reg < 16);
|
||||
int rN = (reg & 0xf) << 12;
|
||||
if (t >= 0 && t < 255) {
|
||||
o4((0xE3A00000 + t) | rN); // mov rN, #0
|
||||
} else if (t >= -256 && t < 0) {
|
||||
size_t encodedImmediate;
|
||||
if (encode12BitImmediate(t, &encodedImmediate)) {
|
||||
o4(0xE3A00000 | encodedImmediate | rN); // mov rN, #0
|
||||
} else if (encode12BitImmediate(-(t+1), &encodedImmediate)) {
|
||||
// mvn means move constant ^ ~0
|
||||
o4((0xE3E00000 - (t+1)) | rN); // mvn rN, #0
|
||||
o4(0xE3E00000 | encodedImmediate | rN); // mvn rN, #0
|
||||
} else {
|
||||
o4(0xE51F0000 | rN); // ldr rN, .L3
|
||||
o4(0xEA000000); // b .L99
|
||||
o4(t); // .L3: .word 0
|
||||
o4(0xE51F0000 | rN); // ldr rN, .L3
|
||||
o4(0xEA000000); // b .L99
|
||||
o4(t); // .L3: .word 0
|
||||
// .L99:
|
||||
}
|
||||
}
|
||||
|
||||
bool encode12BitImmediate(size_t immediate, size_t* pResult) {
|
||||
for(size_t i = 0; i < 16; i++) {
|
||||
size_t rotate = i * 2;
|
||||
size_t mask = rotateRight(0xff, rotate);
|
||||
if ((immediate | mask) == mask) {
|
||||
size_t bits8 = rotateLeft(immediate, rotate);
|
||||
assert(bits8 <= 0xff);
|
||||
*pResult = (i << 8) | bits8;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t rotateRight(size_t n, size_t rotate) {
|
||||
return (n >> rotate) | (n << (32 - rotate));
|
||||
}
|
||||
|
||||
size_t rotateLeft(size_t n, size_t rotate) {
|
||||
return (n << rotate) | (n >> (32 - rotate));
|
||||
}
|
||||
|
||||
void callRuntime(void* fn) {
|
||||
o4(0xE59FC000); // ldr r12, .L1
|
||||
o4(0xEA000000); // b .L99
|
||||
|
@ -2016,6 +2046,10 @@ class Compiler : public ErrorSink {
|
|||
return a % b;
|
||||
}
|
||||
|
||||
static void runtime_structCopy(void* src, size_t size, void* dest) {
|
||||
memcpy(dest, src, size);
|
||||
}
|
||||
|
||||
#ifndef ARM_USE_VFP
|
||||
|
||||
// Comparison to zero
|
||||
|
@ -2212,6 +2246,13 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
|
||||
virtual void addStructOffsetR0(int offset, Type* pType) {
|
||||
if (offset) {
|
||||
oad(0x05, offset); // addl offset, %eax
|
||||
}
|
||||
setR0Type(pType, ET_LVALUE);
|
||||
}
|
||||
|
||||
virtual int gjmp(int t) {
|
||||
return psym(0xe9, t);
|
||||
}
|
||||
|
@ -2537,6 +2578,26 @@ class Compiler : public ErrorSink {
|
|||
case TY_DOUBLE:
|
||||
o(0x19dd); /* fstpl (%ecx) */
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
{
|
||||
// TODO: use alignment information to use movsw/movsl instead of movsb
|
||||
int size = sizeOf(pTargetType);
|
||||
if (size > 0) {
|
||||
o(0x9c); // pushf
|
||||
o(0x57); // pushl %edi
|
||||
o(0x56); // pushl %esi
|
||||
o(0xcf89); // movl %ecx, %edi
|
||||
o(0xc689); // movl %eax, %esi
|
||||
oad(0xb9, size); // mov #size, %ecx
|
||||
o(0xfc); // cld
|
||||
o(0xf3); // rep
|
||||
o(0xa4); // movsb
|
||||
o(0x5e); // popl %esi
|
||||
o(0x5f); // popl %edi
|
||||
o(0x9d); // popf
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("storeR0ToTOS: unsupported type %d",
|
||||
pTargetType->tag);
|
||||
|
@ -2571,6 +2632,8 @@ class Compiler : public ErrorSink {
|
|||
case TY_ARRAY:
|
||||
pNewType = pNewType->pTail;
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
break;
|
||||
default:
|
||||
error("loadR0FromR0: unsupported type %d", tag);
|
||||
break;
|
||||
|
@ -2747,6 +2810,8 @@ class Compiler : public ErrorSink {
|
|||
return 2;
|
||||
case TY_ARRAY:
|
||||
return alignmentOf(pType->pHead);
|
||||
case TY_STRUCT:
|
||||
return pType->pHead->alignment & 0x7fffffff;
|
||||
case TY_FUNC:
|
||||
error("alignment of func not supported");
|
||||
return 1;
|
||||
|
@ -2774,30 +2839,14 @@ class Compiler : public ErrorSink {
|
|||
return 4;
|
||||
case TY_ARRAY:
|
||||
return pType->length * sizeOf(pType->pHead);
|
||||
case TY_STRUCT:
|
||||
return pType->pHead->length;
|
||||
default:
|
||||
error("Unsupported type %d", pType->tag);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t stackAlignmentOf(Type* pType){
|
||||
return 4;
|
||||
}
|
||||
|
||||
virtual size_t stackSizeOf(Type* pType) {
|
||||
switch(pType->tag) {
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_ARRAY:
|
||||
return sizeOf(pType);
|
||||
case TY_FUNC:
|
||||
error("stackSizeOf func not supported");
|
||||
return 4;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** Output 1 to 4 bytes.
|
||||
|
@ -2926,6 +2975,11 @@ class Compiler : public ErrorSink {
|
|||
mpBase->loadFloat(address, pType);
|
||||
}
|
||||
|
||||
virtual void addStructOffsetR0(int offset, Type* pType) {
|
||||
fprintf(stderr, "addStructOffsetR0(%d, type=%d)\n", offset, pType->tag);
|
||||
mpBase->addStructOffsetR0(offset, pType);
|
||||
}
|
||||
|
||||
virtual int gjmp(int t) {
|
||||
int result = mpBase->gjmp(t);
|
||||
fprintf(stderr, "gjmp(%d) = %d\n", t, result);
|
||||
|
@ -3073,16 +3127,6 @@ class Compiler : public ErrorSink {
|
|||
return mpBase->sizeOf(pType);
|
||||
}
|
||||
|
||||
|
||||
virtual size_t stackAlignmentOf(Type* pType) {
|
||||
return mpBase->stackAlignmentOf(pType);
|
||||
}
|
||||
|
||||
|
||||
virtual size_t stackSizeOf(Type* pType) {
|
||||
return mpBase->stackSizeOf(pType);
|
||||
}
|
||||
|
||||
virtual Type* getR0Type() {
|
||||
return mpBase->getR0Type();
|
||||
}
|
||||
|
@ -3236,6 +3280,7 @@ class Compiler : public ErrorSink {
|
|||
// Current values for the token
|
||||
char* mpMacroDefinition;
|
||||
VariableInfo* mpVariableInfo;
|
||||
VariableInfo* mpStructInfo;
|
||||
};
|
||||
|
||||
class TokenTable {
|
||||
|
@ -3516,6 +3561,7 @@ class Compiler : public ErrorSink {
|
|||
size_t level;
|
||||
VariableInfo* pOldDefinition;
|
||||
Type* pType;
|
||||
bool isStructTag;
|
||||
};
|
||||
|
||||
class SymbolStack {
|
||||
|
@ -3547,7 +3593,11 @@ class Compiler : public ErrorSink {
|
|||
while (mStack.size() > mark.mSymbolHead) {
|
||||
VariableInfo* pV = mStack.back();
|
||||
mStack.pop_back();
|
||||
(*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
|
||||
if (pV->isStructTag) {
|
||||
(*mpTokenTable)[pV->tok].mpStructInfo = pV->pOldDefinition;
|
||||
} else {
|
||||
(*mpTokenTable)[pV->tok].mpVariableInfo = pV->pOldDefinition;
|
||||
}
|
||||
}
|
||||
mpArena->freeToMark(mark.mArenaMark);
|
||||
}
|
||||
|
@ -3557,6 +3607,11 @@ class Compiler : public ErrorSink {
|
|||
return pV && pV->level == level();
|
||||
}
|
||||
|
||||
bool isStructTagDefinedAtCurrentLevel(tokenid_t tok) {
|
||||
VariableInfo* pV = (*mpTokenTable)[tok].mpStructInfo;
|
||||
return pV && pV->level == level();
|
||||
}
|
||||
|
||||
VariableInfo* add(tokenid_t tok) {
|
||||
Token& token = (*mpTokenTable)[tok];
|
||||
VariableInfo* pOldV = token.mpVariableInfo;
|
||||
|
@ -3571,6 +3626,21 @@ class Compiler : public ErrorSink {
|
|||
return pNewV;
|
||||
}
|
||||
|
||||
VariableInfo* addStructTag(tokenid_t tok) {
|
||||
Token& token = (*mpTokenTable)[tok];
|
||||
VariableInfo* pOldS = token.mpStructInfo;
|
||||
VariableInfo* pNewS =
|
||||
(VariableInfo*) mpArena->alloc(sizeof(VariableInfo));
|
||||
memset(pNewS, 0, sizeof(VariableInfo));
|
||||
pNewS->tok = tok;
|
||||
pNewS->level = level();
|
||||
pNewS->isStructTag = true;
|
||||
pNewS->pOldDefinition = pOldS;
|
||||
token.mpStructInfo = pNewS;
|
||||
mStack.push_back(pNewS);
|
||||
return pNewS;
|
||||
}
|
||||
|
||||
VariableInfo* add(Type* pType) {
|
||||
VariableInfo* pVI = add(pType->id);
|
||||
pVI->pType = pType;
|
||||
|
@ -3629,6 +3699,8 @@ class Compiler : public ErrorSink {
|
|||
SymbolStack mGlobals;
|
||||
SymbolStack mLocals;
|
||||
|
||||
SymbolStack* mpCurrentSymbolStack;
|
||||
|
||||
// Prebuilt types, makes things slightly faster.
|
||||
Type* mkpInt; // int
|
||||
Type* mkpShort; // short
|
||||
|
@ -3663,6 +3735,7 @@ class Compiler : public ErrorSink {
|
|||
static const int TOK_NUM_FLOAT = 3;
|
||||
static const int TOK_NUM_DOUBLE = 4;
|
||||
static const int TOK_OP_ASSIGNMENT = 5;
|
||||
static const int TOK_OP_ARROW = 6;
|
||||
|
||||
// 3..255 are character and/or operators
|
||||
|
||||
|
@ -4000,6 +4073,9 @@ class Compiler : public ErrorSink {
|
|||
mTokenString.clear();
|
||||
pdef(ch);
|
||||
inp();
|
||||
if (tok == '.' && !isdigit(ch)) {
|
||||
goto done;
|
||||
}
|
||||
int base = 10;
|
||||
if (tok == '0') {
|
||||
if (ch == 'x' || ch == 'X') {
|
||||
|
@ -4088,6 +4164,9 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
inp();
|
||||
next();
|
||||
} else if ((tok == '-') & (ch == '>')) {
|
||||
inp();
|
||||
tok = TOK_OP_ARROW;
|
||||
} else {
|
||||
const char* t = operatorChars;
|
||||
int opIndex = 0;
|
||||
|
@ -4121,6 +4200,8 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
done: ;
|
||||
#if 0
|
||||
{
|
||||
String buf;
|
||||
|
@ -4443,6 +4524,24 @@ class Compiler : public ErrorSink {
|
|||
pGen->genOp(OP_PLUS);
|
||||
doPointer();
|
||||
skip(']');
|
||||
} else if (accept('.')) {
|
||||
// struct element
|
||||
pGen->forceR0RVal();
|
||||
Type* pStruct = pGen->getR0Type();
|
||||
if (pStruct->tag == TY_STRUCT) {
|
||||
doStructMember(pStruct);
|
||||
} else {
|
||||
error("expected a struct value to the left of '.'");
|
||||
}
|
||||
} else if (accept(TOK_OP_ARROW)) {
|
||||
pGen->forceR0RVal();
|
||||
Type* pPtr = pGen->getR0Type();
|
||||
if (pPtr->tag == TY_POINTER && pPtr->pHead->tag == TY_STRUCT) {
|
||||
pGen->loadR0FromR0();
|
||||
doStructMember(pPtr->pHead);
|
||||
} else {
|
||||
error("Expected a pointer to a struct to the left of '->'");
|
||||
}
|
||||
} else if (accept('(')) {
|
||||
/* function call */
|
||||
Type* pDecl = NULL;
|
||||
|
@ -4505,6 +4604,18 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
|
||||
void doStructMember(Type* pStruct) {
|
||||
Type* pStructElement = lookupStructMember(pStruct, tok);
|
||||
if (pStructElement) {
|
||||
next();
|
||||
pGen->addStructOffsetR0(pStructElement->length, createPtrType(pStructElement->pHead));
|
||||
} else {
|
||||
String buf;
|
||||
decodeToken(buf, tok, true);
|
||||
error("Expected a struct member to the right of '.', got %s", buf.getUnwrapped());
|
||||
}
|
||||
}
|
||||
|
||||
void doIncDec(int isInc, int isPost) {
|
||||
// R0 already has the lval
|
||||
checkLVal();
|
||||
|
@ -4714,6 +4825,8 @@ class Compiler : public ErrorSink {
|
|||
} else if (at == TY_FUNC || at == TY_PARAM) {
|
||||
return typeEqual(a->pHead, b->pHead)
|
||||
&& typeEqual(a->pTail, b->pTail);
|
||||
} else if (at == TY_STRUCT) {
|
||||
return a->pHead == b->pHead;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -4746,20 +4859,22 @@ class Compiler : public ErrorSink {
|
|||
|
||||
void decodeTypeImp(String& buffer, Type* pType) {
|
||||
decodeTypeImpPrefix(buffer, pType);
|
||||
decodeId(buffer, pType->id);
|
||||
decodeTypeImpPostfix(buffer, pType);
|
||||
}
|
||||
|
||||
String temp;
|
||||
if (pType->id != 0) {
|
||||
decodeToken(temp, pType->id, false);
|
||||
void decodeId(String& buffer, tokenid_t id) {
|
||||
if (id) {
|
||||
String temp;
|
||||
decodeToken(temp, id, false);
|
||||
buffer.append(temp);
|
||||
}
|
||||
|
||||
decodeTypeImpPostfix(buffer, pType);
|
||||
}
|
||||
|
||||
void decodeTypeImpPrefix(String& buffer, Type* pType) {
|
||||
TypeTag tag = pType->tag;
|
||||
|
||||
if (tag >= TY_INT && tag <= TY_DOUBLE) {
|
||||
if ((tag >= TY_INT && tag <= TY_DOUBLE) || tag == TY_STRUCT) {
|
||||
switch (tag) {
|
||||
case TY_INT:
|
||||
buffer.appendCStr("int");
|
||||
|
@ -4779,6 +4894,16 @@ class Compiler : public ErrorSink {
|
|||
case TY_DOUBLE:
|
||||
buffer.appendCStr("double");
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
{
|
||||
bool isStruct = (pType->pHead->alignment & 0x80000000) != 0;
|
||||
buffer.appendCStr(isStruct ? "struct" : "union");
|
||||
if (pType->pHead && pType->pHead->structTag) {
|
||||
buffer.append(' ');
|
||||
decodeId(buffer, pType->pHead->structTag);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -4808,6 +4933,8 @@ class Compiler : public ErrorSink {
|
|||
case TY_ARRAY:
|
||||
decodeTypeImpPrefix(buffer, pType->pHead);
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
break;
|
||||
case TY_FUNC:
|
||||
decodeTypeImp(buffer, pType->pHead);
|
||||
break;
|
||||
|
@ -4839,6 +4966,16 @@ class Compiler : public ErrorSink {
|
|||
buffer.append(temp);
|
||||
}
|
||||
break;
|
||||
case TY_STRUCT:
|
||||
if (pType->pHead->length >= 0) {
|
||||
buffer.appendCStr(" {");
|
||||
for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
|
||||
decodeTypeImp(buffer, pArg->pHead);
|
||||
buffer.appendCStr(";");
|
||||
}
|
||||
buffer.append('}');
|
||||
}
|
||||
break;
|
||||
case TY_FUNC:
|
||||
buffer.append('(');
|
||||
for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
|
||||
|
@ -4874,6 +5011,8 @@ class Compiler : public ErrorSink {
|
|||
pType = mkpFloat;
|
||||
} else if (tok == TOK_DOUBLE) {
|
||||
pType = mkpDouble;
|
||||
} else if (tok == TOK_STRUCT || tok == TOK_UNION) {
|
||||
return acceptStruct();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4881,6 +5020,123 @@ class Compiler : public ErrorSink {
|
|||
return pType;
|
||||
}
|
||||
|
||||
Type* acceptStruct() {
|
||||
assert(tok == TOK_STRUCT || tok == TOK_UNION);
|
||||
bool isStruct = tok == TOK_STRUCT;
|
||||
next();
|
||||
tokenid_t structTag = acceptSymbol();
|
||||
bool isDeclaration = accept('{');
|
||||
bool fail = false;
|
||||
|
||||
Type* pStructType = createType(TY_STRUCT, NULL, NULL);
|
||||
if (structTag) {
|
||||
Token* pToken = &mTokenTable[structTag];
|
||||
VariableInfo* pStructInfo = pToken->mpStructInfo;
|
||||
bool needToDeclare = !pStructInfo;
|
||||
if (pStructInfo) {
|
||||
if (isDeclaration) {
|
||||
if (mpCurrentSymbolStack->isStructTagDefinedAtCurrentLevel(structTag)) {
|
||||
if (pStructInfo->pType->pHead->length == -1) {
|
||||
// we're filling in a forward declaration.
|
||||
needToDeclare = false;
|
||||
} else {
|
||||
error("A struct with the same name is already defined at this level.");
|
||||
fail = true;
|
||||
}
|
||||
} else {
|
||||
needToDeclare = true;
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
assert(pStructInfo->isStructTag);
|
||||
pStructType->pHead = pStructInfo->pType;
|
||||
pStructType->pTail = pStructType->pHead->pTail;
|
||||
}
|
||||
}
|
||||
|
||||
if (needToDeclare) {
|
||||
// This is a new struct name
|
||||
pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag);
|
||||
pStructType = createType(TY_STRUCT, NULL, NULL);
|
||||
pStructType->structTag = structTag;
|
||||
pStructType->pHead = pStructType;
|
||||
if (! isDeclaration) {
|
||||
// A forward declaration
|
||||
pStructType->length = -1;
|
||||
}
|
||||
pToken->mpStructInfo->pType = pStructType;
|
||||
}
|
||||
} else {
|
||||
// An anonymous struct
|
||||
pStructType->pHead = pStructType;
|
||||
}
|
||||
|
||||
if (isDeclaration) {
|
||||
size_t offset = 0;
|
||||
size_t structSize = 0;
|
||||
size_t structAlignment = 0;
|
||||
Type** pParamHolder = & pStructType->pHead->pTail;
|
||||
while (tok != '}' && tok != EOF) {
|
||||
Type* pPrimitiveType = expectPrimitiveType();
|
||||
if (pPrimitiveType) {
|
||||
while (tok != ';' && tok != EOF) {
|
||||
Type* pItem = acceptDeclaration(pPrimitiveType, true, false);
|
||||
if (!pItem) {
|
||||
break;
|
||||
}
|
||||
if (lookupStructMember(pStructType, pItem->id)) {
|
||||
String buf;
|
||||
decodeToken(buf, pItem->id, false);
|
||||
error("Duplicate struct member %s", buf.getUnwrapped());
|
||||
}
|
||||
Type* pStructElement = createType(TY_PARAM, pItem, NULL);
|
||||
size_t alignment = pGen->alignmentOf(pItem);
|
||||
if (alignment > structAlignment) {
|
||||
structAlignment = alignment;
|
||||
}
|
||||
size_t alignmentMask = alignment - 1;
|
||||
offset = (offset + alignmentMask) & ~alignmentMask;
|
||||
pStructElement->length = offset;
|
||||
size_t size = pGen->sizeOf(pItem);
|
||||
if (isStruct) {
|
||||
offset += size;
|
||||
structSize = offset;
|
||||
} else {
|
||||
if (size >= structSize) {
|
||||
structSize = size;
|
||||
}
|
||||
}
|
||||
*pParamHolder = pStructElement;
|
||||
pParamHolder = &pStructElement->pTail;
|
||||
accept(',');
|
||||
}
|
||||
skip(';');
|
||||
} else {
|
||||
// Some sort of syntax error, skip token and keep trying
|
||||
next();
|
||||
}
|
||||
}
|
||||
if (!fail) {
|
||||
pStructType->pHead->length = structSize;
|
||||
pStructType->pHead->alignment = structAlignment | (isStruct << 31);
|
||||
}
|
||||
skip('}');
|
||||
}
|
||||
if (fail) {
|
||||
pStructType = NULL;
|
||||
}
|
||||
return pStructType;
|
||||
}
|
||||
|
||||
Type* lookupStructMember(Type* pStruct, tokenid_t memberId) {
|
||||
for(Type* pStructElement = pStruct->pHead->pTail; pStructElement; pStructElement = pStructElement->pTail) {
|
||||
if (pStructElement->pHead->id == memberId) {
|
||||
return pStructElement;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) {
|
||||
tokenid_t declName = 0;
|
||||
bool reportFailure = false;
|
||||
|
@ -4890,14 +5146,15 @@ class Compiler : public ErrorSink {
|
|||
// Clone the parent type so we can set a unique ID
|
||||
Type* pOldType = pType;
|
||||
pType = createType(pType->tag, pType->pHead, pType->pTail);
|
||||
|
||||
*pType = *pOldType;
|
||||
pType->id = declName;
|
||||
pType->length = pOldType->length;
|
||||
} else if (nameRequired) {
|
||||
error("Expected a variable name");
|
||||
}
|
||||
// fprintf(stderr, "Parsed a declaration: ");
|
||||
// printType(pType);
|
||||
#if 0
|
||||
fprintf(stderr, "Parsed a declaration: ");
|
||||
printType(pType);
|
||||
#endif
|
||||
if (reportFailure) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -4905,7 +5162,8 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
|
||||
Type* expectDeclaration(Type* pBaseType) {
|
||||
Type* pType = acceptDeclaration(pBaseType, true, true);
|
||||
bool nameRequired = pBaseType->tag != TY_STRUCT;
|
||||
Type* pType = acceptDeclaration(pBaseType, true, nameRequired);
|
||||
if (! pType) {
|
||||
error("Expected a declaration");
|
||||
}
|
||||
|
@ -4962,6 +5220,7 @@ class Compiler : public ErrorSink {
|
|||
String temp;
|
||||
decodeToken(temp, tok, true);
|
||||
error("Expected name. Got %s", temp.getUnwrapped());
|
||||
assert(false);
|
||||
reportFailure = true;
|
||||
}
|
||||
for(;;) {
|
||||
|
@ -5069,11 +5328,16 @@ class Compiler : public ErrorSink {
|
|||
if (!pDecl) {
|
||||
break;
|
||||
}
|
||||
if (!pDecl->id) {
|
||||
break;
|
||||
}
|
||||
int variableAddress = 0;
|
||||
addLocalSymbol(pDecl);
|
||||
size_t alignment = pGen->stackAlignmentOf(pDecl);
|
||||
size_t alignment = pGen->alignmentOf(pDecl);
|
||||
assert(alignment > 0);
|
||||
size_t alignmentMask = ~ (alignment - 1);
|
||||
size_t sizeOf = pGen->sizeOf(pDecl);
|
||||
assert(sizeOf > 0);
|
||||
loc = (loc + alignment - 1) & alignmentMask;
|
||||
size_t alignedSize = (sizeOf + alignment - 1) & alignmentMask;
|
||||
loc = loc + alignedSize;
|
||||
|
@ -5123,6 +5387,12 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
|
||||
void printToken(tokenid_t token) {
|
||||
String buffer;
|
||||
decodeToken(buffer, token, true);
|
||||
fprintf(stderr, "%s\n", buffer.getUnwrapped());
|
||||
}
|
||||
|
||||
bool checkSymbol(tokenid_t token) {
|
||||
bool result = token >= TOK_SYMBOL;
|
||||
if (!result) {
|
||||
|
@ -5143,6 +5413,7 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
|
||||
void globalDeclarations() {
|
||||
mpCurrentSymbolStack = &mGlobals;
|
||||
while (tok != EOF) {
|
||||
Type* pBaseType = expectPrimitiveType();
|
||||
if (!pBaseType) {
|
||||
|
@ -5152,6 +5423,11 @@ class Compiler : public ErrorSink {
|
|||
if (!pDecl) {
|
||||
break;
|
||||
}
|
||||
if (!pDecl->id) {
|
||||
skip(';');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isDefined(pDecl->id)) {
|
||||
addGlobalSymbol(pDecl);
|
||||
}
|
||||
|
@ -5198,6 +5474,7 @@ class Compiler : public ErrorSink {
|
|||
error("expected '{'");
|
||||
} else {
|
||||
mpCurrentArena = &mLocalArena;
|
||||
mpCurrentSymbolStack = &mLocals;
|
||||
if (name) {
|
||||
/* patch forward references */
|
||||
pGen->resolveForward((int) name->pForward);
|
||||
|
@ -5214,12 +5491,13 @@ class Compiler : public ErrorSink {
|
|||
addLocalSymbol(pArg);
|
||||
}
|
||||
/* read param name and compute offset */
|
||||
size_t alignment = pGen->stackAlignmentOf(pArg);
|
||||
Type* pPassingType = passingType(pArg);
|
||||
size_t alignment = pGen->alignmentOf(pPassingType);
|
||||
a = (a + alignment - 1) & ~ (alignment-1);
|
||||
if (pArg->id) {
|
||||
VI(pArg->id)->pAddress = (void*) a;
|
||||
}
|
||||
a = a + pGen->stackSizeOf(pArg);
|
||||
a = a + pGen->sizeOf(pPassingType);
|
||||
argCount++;
|
||||
}
|
||||
rsym = loc = 0;
|
||||
|
@ -5230,16 +5508,28 @@ class Compiler : public ErrorSink {
|
|||
pGen->functionExit(pDecl, a, loc);
|
||||
mLocals.popLevel();
|
||||
mpCurrentArena = &mGlobalArena;
|
||||
mpCurrentSymbolStack = &mGlobals;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Type* passingType(Type* pType) {
|
||||
switch (pType->tag) {
|
||||
case TY_CHAR:
|
||||
case TY_SHORT:
|
||||
return mkpInt;
|
||||
default:
|
||||
return pType;
|
||||
}
|
||||
}
|
||||
|
||||
char* allocGlobalSpace(size_t alignment, size_t bytes) {
|
||||
size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1);
|
||||
size_t end = base + bytes;
|
||||
if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) {
|
||||
error("Global space exhausted");
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
char* result = (char*) base;
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
// struct definition and declaration
|
||||
struct a {
|
||||
int a;
|
||||
int b;
|
||||
} c;
|
||||
|
||||
// Useless, but legal struct declaration
|
||||
struct {
|
||||
int x;
|
||||
};
|
||||
|
||||
// Useful anonymous struct declaration
|
||||
struct {
|
||||
int y;
|
||||
} anon1, anon2;
|
||||
|
||||
// forward declarations
|
||||
struct a;
|
||||
struct b;
|
||||
struct c;
|
||||
|
||||
struct b {int a; int b; };
|
||||
|
||||
// struct c {b g; }; // syntax error.
|
||||
|
||||
// struct s {float c,a,b,c;} s; // duplicate struct member
|
||||
|
||||
struct c {struct b g; };
|
||||
|
||||
// struct a { int w; }; // error
|
||||
|
||||
void testCopying() {
|
||||
struct a {int a[10]; char c;} a, b;
|
||||
a.c = 37;
|
||||
b.c = 38;
|
||||
b = a;
|
||||
printf("testCopying: %d == %d\n", a.c, b.c);
|
||||
}
|
||||
|
||||
void testUnion() {
|
||||
union u;
|
||||
union u {float f;int i;} u;
|
||||
u.f = 1.0f;
|
||||
printf("testUnion: %g == 0x%08x\n", u.f, u.i);
|
||||
}
|
||||
|
||||
struct v {float x, y, z, w; };
|
||||
|
||||
void add(struct v* result, struct v* a, struct v* b) {
|
||||
result->x = a->x + b->x;
|
||||
result->y = a->y + b->y;
|
||||
result->z = a->z + b->z;
|
||||
result->w = a->w + b->w;
|
||||
}
|
||||
|
||||
void set(struct v* v, float x, float y, float z, float w) {
|
||||
v->x = x;
|
||||
v->y = y;
|
||||
v->z = z;
|
||||
v->w = w;
|
||||
}
|
||||
|
||||
void print(struct v* v) {
|
||||
printf("(%g, %g, %g, %g)\n", v->x, v->y, v->z, v->w);
|
||||
}
|
||||
|
||||
void testArgs() {
|
||||
struct v a, b, c;
|
||||
set(&a, 1.0f, 2.0f, 3.0f, 4.0f);
|
||||
set(&b, 5.0f, 6.0f, 7.0f, 8.0f);
|
||||
add(&c, &a, &b);
|
||||
printf("testArgs: ");
|
||||
print(&c);
|
||||
}
|
||||
|
||||
int main() {
|
||||
anon1.y = 3;
|
||||
anon2.y = anon1.y;
|
||||
|
||||
testCopying();
|
||||
testUnion();
|
||||
testArgs();
|
||||
|
||||
struct c cc;
|
||||
cc.g.a = 3;
|
||||
c.a = 1;
|
||||
c.b = 3;
|
||||
struct a {int x, y; } z;
|
||||
// struct a {int x, y; } z2;
|
||||
z.x = c.a;
|
||||
struct a *pA;
|
||||
pA = &z;
|
||||
pA->x += 5;
|
||||
return pA->x;
|
||||
}
|
|
@ -463,6 +463,13 @@ result: 4
|
|||
result: 1092616192
|
||||
""","""""")
|
||||
|
||||
def testStructs(self):
|
||||
self.compileCheck(["-R", "data/structs.c"], """Executing compiled code:
|
||||
testCopying: 37 == 37
|
||||
testUnion: 1 == 0x3f800000
|
||||
testArgs: (6, 8, 10, 12)
|
||||
result: 6
|
||||
""","""""")
|
||||
|
||||
def main():
|
||||
checkEnvironment()
|
||||
|
|
Loading…
Reference in New Issue