summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Palevich <jackpal@google.com>2009-08-26 16:15:07 -0700
committerJack Palevich <jackpal@google.com>2009-08-26 16:15:07 -0700
commit9221bcccb39a53c8cddf338e53d0cfa2201b52dd (patch)
tree26223c892eeea9bde195a30428f9112222c7d72f
parentc0f253359f11c087a3ffc92b46755c6c96f57899 (diff)
downloadsystem_core-9221bcccb39a53c8cddf338e53d0cfa2201b52dd.zip
system_core-9221bcccb39a53c8cddf338e53d0cfa2201b52dd.tar.gz
system_core-9221bcccb39a53c8cddf338e53d0cfa2201b52dd.tar.bz2
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.
-rw-r--r--libacc/acc.cpp480
-rw-r--r--libacc/tests/data/structs.c95
-rw-r--r--libacc/tests/test.py7
3 files changed, 487 insertions, 95 deletions
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index a4222e6..0409c10 100644
--- a/libacc/acc.cpp
+++ b/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;
diff --git a/libacc/tests/data/structs.c b/libacc/tests/data/structs.c
new file mode 100644
index 0000000..dd81af3
--- /dev/null
+++ b/libacc/tests/data/structs.c
@@ -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;
+}
diff --git a/libacc/tests/test.py b/libacc/tests/test.py
index b8caee0..a8575b1 100644
--- a/libacc/tests/test.py
+++ b/libacc/tests/test.py
@@ -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()