Implement arrays.
Added check to see that pointer types are compatible when passing function arguments.
This commit is contained in:
parent
aa027b4668
commit
b61545096d
211
libacc/acc.cpp
211
libacc/acc.cpp
|
@ -139,16 +139,17 @@ class Compiler : public ErrorSink {
|
|||
TY_VOID, // 3
|
||||
TY_FLOAT, // 4
|
||||
TY_DOUBLE, // 5
|
||||
TY_POINTER, // 6
|
||||
TY_ARRAY, // 7
|
||||
TY_STRUCT, // 8
|
||||
TY_FUNC, // 9
|
||||
TY_PARAM // 10
|
||||
TY_POINTER, // 6
|
||||
TY_ARRAY, // 7
|
||||
TY_STRUCT, // 8
|
||||
TY_FUNC, // 9
|
||||
TY_PARAM // 10
|
||||
};
|
||||
|
||||
struct Type {
|
||||
TypeTag tag;
|
||||
tokenid_t id; // For function arguments (stores length for array)
|
||||
tokenid_t id; // For function arguments, local vars
|
||||
int length; // length of array
|
||||
Type* pHead;
|
||||
Type* pTail;
|
||||
};
|
||||
|
@ -405,7 +406,16 @@ class Compiler : public ErrorSink {
|
|||
/**
|
||||
* Convert R0 to the given type.
|
||||
*/
|
||||
virtual void convertR0(Type* pType) = 0;
|
||||
|
||||
void convertR0(Type* pType) {
|
||||
convertR0Imp(pType, false);
|
||||
}
|
||||
|
||||
void castR0(Type* pType) {
|
||||
convertR0Imp(pType, true);
|
||||
}
|
||||
|
||||
virtual void convertR0Imp(Type* pType, bool isCast) = 0;
|
||||
|
||||
/* Emit code to adjust the stack for a function call. Return the
|
||||
* label for the address of the instruction that adjusts the
|
||||
|
@ -622,14 +632,40 @@ class Compiler : public ErrorSink {
|
|||
return collapseType(getR0Type()->tag);
|
||||
}
|
||||
|
||||
bool isFloatType(Type* pType) {
|
||||
static bool isFloatType(Type* pType) {
|
||||
return isFloatTag(pType->tag);
|
||||
}
|
||||
|
||||
bool isFloatTag(TypeTag tag) {
|
||||
static bool isFloatTag(TypeTag tag) {
|
||||
return tag == TY_FLOAT || tag == TY_DOUBLE;
|
||||
}
|
||||
|
||||
static bool isPointerType(Type* pType) {
|
||||
return isPointerTag(pType->tag);
|
||||
}
|
||||
|
||||
static bool isPointerTag(TypeTag tag) {
|
||||
return tag == TY_POINTER || tag == TY_ARRAY;
|
||||
}
|
||||
|
||||
Type* getPointerArithmeticResultType(Type* a, Type* b) {
|
||||
TypeTag aTag = a->tag;
|
||||
TypeTag bTag = b->tag;
|
||||
if (aTag == TY_POINTER) {
|
||||
return a;
|
||||
}
|
||||
if (bTag == TY_POINTER) {
|
||||
return b;
|
||||
}
|
||||
if (aTag == TY_ARRAY) {
|
||||
return a->pTail;
|
||||
}
|
||||
if (bTag == TY_ARRAY) {
|
||||
return b->pTail;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Type* mkpInt;
|
||||
|
||||
private:
|
||||
|
@ -848,8 +884,8 @@ class Compiler : public ErrorSink {
|
|||
bool isFloatTOS = isFloatTag(tagTOS);
|
||||
if (!isFloatR0 && !isFloatTOS) {
|
||||
setupIntPtrArgs();
|
||||
bool isPtrR0 = tagR0 == TY_POINTER;
|
||||
bool isPtrTOS = tagTOS == TY_POINTER;
|
||||
bool isPtrR0 = isPointerTag(tagR0);
|
||||
bool isPtrTOS = isPointerTag(tagTOS);
|
||||
if (isPtrR0 || isPtrTOS) {
|
||||
if (isPtrR0 && isPtrTOS) {
|
||||
if (op != OP_MINUS) {
|
||||
|
@ -871,7 +907,8 @@ class Compiler : public ErrorSink {
|
|||
if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
|
||||
error("Unsupported pointer-scalar operation %d", op);
|
||||
}
|
||||
Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
|
||||
Type* pPtrType = getPointerArithmeticResultType(
|
||||
pR0Type, pTOSType);
|
||||
int size = sizeOf(pPtrType->pHead);
|
||||
if (size != 1) {
|
||||
// TODO: Optimize for power-of-two.
|
||||
|
@ -1131,7 +1168,8 @@ class Compiler : public ErrorSink {
|
|||
virtual void loadR0FromR0() {
|
||||
Type* pPointerType = getR0Type();
|
||||
assert(pPointerType->tag == TY_POINTER);
|
||||
switch (pPointerType->pHead->tag) {
|
||||
TypeTag tag = pPointerType->pHead->tag;
|
||||
switch (tag) {
|
||||
case TY_POINTER:
|
||||
case TY_INT:
|
||||
case TY_FLOAT:
|
||||
|
@ -1147,7 +1185,7 @@ class Compiler : public ErrorSink {
|
|||
o4(0xE1C000D0); // ldrd r0, [r0]
|
||||
break;
|
||||
default:
|
||||
error("loadR0FromR0: unimplemented type");
|
||||
error("loadR0FromR0: unimplemented type %d", tag);
|
||||
break;
|
||||
}
|
||||
setR0Type(pPointerType->pHead);
|
||||
|
@ -1197,9 +1235,27 @@ class Compiler : public ErrorSink {
|
|||
return result;
|
||||
}
|
||||
|
||||
virtual void convertR0(Type* pType){
|
||||
virtual void convertR0Imp(Type* pType, bool isCast){
|
||||
Type* pR0Type = getR0Type();
|
||||
if (bitsSame(pType, pR0Type)) {
|
||||
if (isPointerType(pType) && isPointerType(pR0Type)) {
|
||||
Type* pA = pR0Type;
|
||||
Type* pB = pType;
|
||||
// Array decays to pointer
|
||||
if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
|
||||
pA = pA->pTail;
|
||||
}
|
||||
if (typeEqual(pA, pB)) {
|
||||
return; // OK
|
||||
}
|
||||
if (pB->pHead->tag == TY_VOID) {
|
||||
return; // convert to void* is OK.
|
||||
}
|
||||
if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
|
||||
&& isCast) {
|
||||
return; // OK
|
||||
}
|
||||
error("Incompatible pointer or array types");
|
||||
} else if (bitsSame(pType, pR0Type)) {
|
||||
// do nothing special
|
||||
} else {
|
||||
TypeTag r0Tag = collapseType(pR0Type->tag);
|
||||
|
@ -1423,14 +1479,17 @@ class Compiler : public ErrorSink {
|
|||
return 2;
|
||||
case TY_CHAR:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
case TY_FLOAT:
|
||||
return 4;
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_POINTER:
|
||||
return 4;
|
||||
case TY_ARRAY:
|
||||
return pType->length * sizeOf(pType->pHead);
|
||||
default:
|
||||
error("Unsupported type %d", pType->tag);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1438,6 +1497,8 @@ class Compiler : public ErrorSink {
|
|||
switch(pType->tag) {
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_ARRAY:
|
||||
return stackAlignmentOf(pType->pHead);
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
|
@ -1447,6 +1508,11 @@ class Compiler : public ErrorSink {
|
|||
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;
|
||||
}
|
||||
|
@ -1911,8 +1977,8 @@ class Compiler : public ErrorSink {
|
|||
bool isFloatR0 = isFloatTag(tagR0);
|
||||
bool isFloatTOS = isFloatTag(tagTOS);
|
||||
if (!isFloatR0 && !isFloatTOS) {
|
||||
bool isPtrR0 = tagR0 == TY_POINTER;
|
||||
bool isPtrTOS = tagTOS == TY_POINTER;
|
||||
bool isPtrR0 = isPointerTag(tagR0);
|
||||
bool isPtrTOS = isPointerTag(tagTOS);
|
||||
if (isPtrR0 || isPtrTOS) {
|
||||
if (isPtrR0 && isPtrTOS) {
|
||||
if (op != OP_MINUS) {
|
||||
|
@ -1936,7 +2002,8 @@ class Compiler : public ErrorSink {
|
|||
if (! (op == OP_PLUS || (op == OP_MINUS && isPtrR0))) {
|
||||
error("Unsupported pointer-scalar operation %d", op);
|
||||
}
|
||||
Type* pPtrType = isPtrR0 ? pR0Type : pTOSType;
|
||||
Type* pPtrType = getPointerArithmeticResultType(
|
||||
pR0Type, pTOSType);
|
||||
o(0x59); /* pop %ecx */
|
||||
int size = sizeOf(pPtrType->pHead);
|
||||
if (size != 1) {
|
||||
|
@ -2146,7 +2213,8 @@ class Compiler : public ErrorSink {
|
|||
virtual void loadR0FromR0() {
|
||||
Type* pPointerType = getR0Type();
|
||||
assert(pPointerType->tag == TY_POINTER);
|
||||
switch (pPointerType->pHead->tag) {
|
||||
TypeTag tag = pPointerType->pHead->tag;
|
||||
switch (tag) {
|
||||
case TY_POINTER:
|
||||
case TY_INT:
|
||||
o2(0x008b); /* mov (%eax), %eax */
|
||||
|
@ -2166,7 +2234,7 @@ class Compiler : public ErrorSink {
|
|||
o2(0x00dd); // fldl (%eax)
|
||||
break;
|
||||
default:
|
||||
error("loadR0FromR0: unsupported type");
|
||||
error("loadR0FromR0: unsupported type %d", tag);
|
||||
break;
|
||||
}
|
||||
setR0Type(pPointerType->pHead);
|
||||
|
@ -2183,14 +2251,32 @@ class Compiler : public ErrorSink {
|
|||
return getPC() - 4;
|
||||
}
|
||||
|
||||
virtual void convertR0(Type* pType){
|
||||
virtual void convertR0Imp(Type* pType, bool isCast){
|
||||
Type* pR0Type = getR0Type();
|
||||
if (pR0Type == NULL) {
|
||||
assert(false);
|
||||
setR0Type(pType);
|
||||
return;
|
||||
}
|
||||
if (bitsSame(pType, pR0Type)) {
|
||||
if (isPointerType(pType) && isPointerType(pR0Type)) {
|
||||
Type* pA = pR0Type;
|
||||
Type* pB = pType;
|
||||
// Array decays to pointer
|
||||
if (pA->tag == TY_ARRAY && pB->tag == TY_POINTER) {
|
||||
pA = pA->pTail;
|
||||
}
|
||||
if (typeEqual(pA, pB)) {
|
||||
return; // OK
|
||||
}
|
||||
if (pB->pHead->tag == TY_VOID) {
|
||||
return; // convert to void* is OK.
|
||||
}
|
||||
if (pA->tag == TY_POINTER && pB->tag == TY_POINTER
|
||||
&& isCast) {
|
||||
return; // OK
|
||||
}
|
||||
error("Incompatible pointer or array types");
|
||||
} else if (bitsSame(pType, pR0Type)) {
|
||||
// do nothing special
|
||||
} else if (isFloatType(pType) && isFloatType(pR0Type)) {
|
||||
// do nothing special, both held in same register on x87.
|
||||
|
@ -2326,6 +2412,11 @@ class Compiler : public ErrorSink {
|
|||
return 1;
|
||||
case TY_SHORT:
|
||||
return 2;
|
||||
case TY_ARRAY:
|
||||
return alignmentOf(pType->pHead);
|
||||
case TY_FUNC:
|
||||
error("alignment of func not supported");
|
||||
return 1;
|
||||
default:
|
||||
return 4;
|
||||
}
|
||||
|
@ -2342,14 +2433,17 @@ class Compiler : public ErrorSink {
|
|||
return 2;
|
||||
case TY_CHAR:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
case TY_FLOAT:
|
||||
return 4;
|
||||
case TY_DOUBLE:
|
||||
return 8;
|
||||
case TY_POINTER:
|
||||
return 4;
|
||||
case TY_ARRAY:
|
||||
return pType->length * sizeOf(pType->pHead);
|
||||
default:
|
||||
error("Unsupported type %d", pType->tag);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2361,6 +2455,11 @@ class Compiler : public ErrorSink {
|
|||
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;
|
||||
}
|
||||
|
@ -3911,7 +4010,7 @@ class Compiler : public ErrorSink {
|
|||
skip(')');
|
||||
unary();
|
||||
pGen->forceR0RVal();
|
||||
pGen->convertR0(pCast);
|
||||
pGen->castR0(pCast);
|
||||
} else {
|
||||
commaExpr();
|
||||
skip(')');
|
||||
|
@ -3959,10 +4058,18 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
}
|
||||
// load a variable
|
||||
Type* pVal = createPtrType(pVI->pType);
|
||||
Type* pVal;
|
||||
ExpressionType et;
|
||||
if (pVI->pType->tag == TY_ARRAY) {
|
||||
pVal = pVI->pType;
|
||||
et = ET_RVALUE;
|
||||
} else {
|
||||
pVal = createPtrType(pVI->pType);
|
||||
et = ET_LVALUE;
|
||||
}
|
||||
if (n) {
|
||||
ExpressionType et = ET_LVALUE;
|
||||
if (pVal->pHead->tag == TY_FUNC) {
|
||||
int tag = pVal->pHead->tag;
|
||||
if (tag == TY_FUNC) {
|
||||
et = ET_RVALUE;
|
||||
}
|
||||
pGen->leaR0(n, pVal, et);
|
||||
|
@ -4251,6 +4358,8 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
if (at == TY_POINTER) {
|
||||
return typeEqual(a->pHead, b->pHead);
|
||||
} else if (at == TY_ARRAY) {
|
||||
return a->length == b->length && typeEqual(a->pHead, b->pHead);
|
||||
} else if (at == TY_FUNC || at == TY_PARAM) {
|
||||
return typeEqual(a->pHead, b->pHead)
|
||||
&& typeEqual(a->pTail, b->pTail);
|
||||
|
@ -4345,6 +4454,9 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
buffer.append('*');
|
||||
break;
|
||||
case TY_ARRAY:
|
||||
decodeTypeImpPrefix(buffer, pType->pHead);
|
||||
break;
|
||||
case TY_FUNC:
|
||||
decodeTypeImp(buffer, pType->pHead);
|
||||
break;
|
||||
|
@ -4369,6 +4481,13 @@ class Compiler : public ErrorSink {
|
|||
}
|
||||
decodeTypeImpPostfix(buffer, pType->pHead);
|
||||
break;
|
||||
case TY_ARRAY:
|
||||
{
|
||||
String temp;
|
||||
temp.printf("[%d]", pType->length);
|
||||
buffer.append(temp);
|
||||
}
|
||||
break;
|
||||
case TY_FUNC:
|
||||
buffer.append('(');
|
||||
for(Type* pArg = pType->pTail; pArg; pArg = pArg->pTail) {
|
||||
|
@ -4418,9 +4537,13 @@ class Compiler : public ErrorSink {
|
|||
nameRequired, reportFailure);
|
||||
if (declName) {
|
||||
// Clone the parent type so we can set a unique ID
|
||||
Type* pOldType = pType;
|
||||
pType = createType(pType->tag, pType->pHead, pType->pTail);
|
||||
|
||||
pType->id = declName;
|
||||
pType->length = pOldType->length;
|
||||
} else if (nameRequired) {
|
||||
error("Expected a variable name");
|
||||
}
|
||||
// fprintf(stderr, "Parsed a declaration: ");
|
||||
// printType(pType);
|
||||
|
@ -4490,11 +4613,27 @@ class Compiler : public ErrorSink {
|
|||
error("Expected name. Got %s", temp.getUnwrapped());
|
||||
reportFailure = true;
|
||||
}
|
||||
while (accept('(')) {
|
||||
// Function declaration
|
||||
Type* pTail = acceptArgs(nameAllowed);
|
||||
pType = createType(TY_FUNC, pType, pTail);
|
||||
skip(')');
|
||||
for(;;) {
|
||||
if (accept('(')) {
|
||||
// Function declaration
|
||||
Type* pTail = acceptArgs(nameAllowed);
|
||||
pType = createType(TY_FUNC, pType, pTail);
|
||||
skip(')');
|
||||
} if (accept('[')) {
|
||||
if (tok != ']') {
|
||||
if (tok != TOK_NUM || tokc <= 0) {
|
||||
error("Expected positive integer constant");
|
||||
} else {
|
||||
Type* pDecayType = createPtrType(pType);
|
||||
pType = createType(TY_ARRAY, pType, pDecayType);
|
||||
pType->length = tokc;
|
||||
}
|
||||
next();
|
||||
}
|
||||
skip(']');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pNewHead) {
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// Array allocation tests
|
||||
|
||||
void testLocalInt()
|
||||
{
|
||||
int a[3];
|
||||
a[0] = 1;
|
||||
a[1] = 2;
|
||||
a[2] = a[0] + a[1];
|
||||
printf("localInt: %d\n", a[2]);
|
||||
}
|
||||
|
||||
char a[3];
|
||||
double d[3];
|
||||
|
||||
void testGlobalChar()
|
||||
{
|
||||
a[0] = 1;
|
||||
a[1] = 2;
|
||||
a[2] = a[0] + a[1];
|
||||
printf("globalChar: %d\n", a[2]);
|
||||
}
|
||||
|
||||
void testGlobalDouble()
|
||||
{
|
||||
d[0] = 1;
|
||||
d[1] = 2;
|
||||
d[2] = d[0] + d[1];
|
||||
printf("globalDouble: %g\n", d[2]);
|
||||
}
|
||||
|
||||
void testLocalDouble()
|
||||
{
|
||||
double d[3];
|
||||
float m[12];
|
||||
m[0] = 1.0f;
|
||||
m[1] = 2.0f;
|
||||
d[0] = 1.0;
|
||||
d[1] = 2.0;
|
||||
d[2] = d[0] + d[1];
|
||||
m[2] = m[0] + m[1];
|
||||
printf("localDouble: %g %g\n", d[2], m[2]);
|
||||
}
|
||||
|
||||
void vectorAdd(int* a, int* b, float* c, int len) {
|
||||
int i;
|
||||
for(i = 0; i < len; i++) {
|
||||
c[i] = a[i] + b[i];
|
||||
}
|
||||
}
|
||||
|
||||
void testArgs() {
|
||||
int a[3], b[3];
|
||||
float c[3];
|
||||
int i;
|
||||
int len = 3;
|
||||
for(i = 0; i < len; i++) {
|
||||
a[i] = i;
|
||||
b[i] = i;
|
||||
c[i] = 0;
|
||||
}
|
||||
vectorAdd(a,b,c, len);
|
||||
printf("testArgs:");
|
||||
for(i = 0; i < len; i++) {
|
||||
printf(" %g", c[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
testLocalInt();
|
||||
testLocalDouble();
|
||||
testGlobalChar();
|
||||
testGlobalDouble();
|
||||
testArgs();
|
||||
return 0;
|
||||
}
|
|
@ -385,6 +385,16 @@ result: 0
|
|||
def testShort(self):
|
||||
self.compileCheck(["-R", "data/short.c"], """Executing compiled code:
|
||||
result: -2
|
||||
""","""""")
|
||||
|
||||
def testArray(self):
|
||||
self.compileCheck(["-R", "data/array.c"], """Executing compiled code:
|
||||
localInt: 3
|
||||
localDouble: 3 3
|
||||
globalChar: 3
|
||||
globalDouble: 3
|
||||
testArgs: 0 2 4
|
||||
result: 0
|
||||
""","""""")
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in New Issue