diff --git a/libacc/FEATURES b/libacc/FEATURES index ce48c6f9c..20f9d987b 100644 --- a/libacc/FEATURES +++ b/libacc/FEATURES @@ -43,6 +43,8 @@ Supported C language subset: - arrays are supported - long doubles are not supported - structs and unions are supported + - typedef is supported + - explicit storage class specifiers are not supported: register, auto, static, extern - Unknown functions and variables are bound at compile time by calling back to the caller. For the 'acc' command-line tool unknown functions diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 09ce64d16..d9cecdd6c 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -151,6 +151,7 @@ public: class Compiler : public ErrorSink { typedef int tokenid_t; enum TypeTag { + TY_UNKNOWN = -1, TY_INT, // 0 TY_CHAR, // 1 TY_SHORT, // 2 @@ -164,8 +165,18 @@ class Compiler : public ErrorSink { TY_PARAM // 10 }; + enum StorageClass { + SC_DEFAULT, // 0 + SC_AUTO, // 1 + SC_REGISTER, // 2 + SC_STATIC, // 3 + SC_EXTERN, // 4 + SC_TYPEDEF // 5 + }; + struct Type { TypeTag tag; + StorageClass storageClass; 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 @@ -4996,7 +5007,7 @@ class Compiler : public ErrorSink { intptr_t a, n, t; Type* pBaseType; - if ((pBaseType = acceptPrimitiveType())) { + if ((pBaseType = acceptPrimitiveType(true))) { /* declarations */ localDeclarations(pBaseType); } else if (tok == TOK_IF) { @@ -5102,9 +5113,10 @@ class Compiler : public ErrorSink { } Type* createType(TypeTag tag, Type* pHead, Type* pTail) { - assert(tag >= TY_INT && tag <= TY_PARAM); + assert(tag >= TY_UNKNOWN && tag <= TY_PARAM); Type* pType = (Type*) mpCurrentArena->alloc(sizeof(Type)); memset(pType, 0, sizeof(*pType)); + pType->storageClass = SC_DEFAULT; pType->tag = tag; pType->pHead = pHead; pType->pTail = pTail; @@ -5267,38 +5279,124 @@ class Compiler : public ErrorSink { fprintf(stderr, "%s\n", buffer.getUnwrapped()); } - Type* acceptPrimitiveType() { - Type* pType; - if (tok == TOK_INT) { - pType = mkpInt; - } else if (tok == TOK_SHORT) { - pType = mkpShort; - } else if (tok == TOK_CHAR) { - pType = mkpChar; - } else if (tok == TOK_VOID) { - pType = mkpVoid; - } else if (tok == TOK_FLOAT) { - pType = mkpFloat; - } else if (tok == TOK_DOUBLE) { - pType = mkpDouble; - } else if (tok == TOK_STRUCT || tok == TOK_UNION) { - return acceptStruct(); + void insertTypeSpecifier(Type** ppType, TypeTag tag) { + if (! *ppType) { + *ppType = createType(tag, NULL, NULL); } else { - return NULL; + if ((*ppType)->tag != TY_UNKNOWN) { + error("Only one type specifier allowed."); + } else { + (*ppType)->tag = tag; + } + } + } + + void insertStorageClass(Type** ppType, StorageClass storageClass) { + if (! *ppType) { + *ppType = createType(TY_UNKNOWN, NULL, NULL); + } + if ((*ppType)->storageClass != SC_DEFAULT) { + error("Only one storage class allowed."); + } else { + (*ppType)->storageClass = storageClass; + } + } + + Type* acceptPrimitiveType(bool allowStorageClass) { + Type* pType = NULL; + for (bool keepGoing = true; keepGoing;) { + switch(tok) { + case TOK_AUTO: + insertStorageClass(&pType, SC_AUTO); + break; + case TOK_REGISTER: + insertStorageClass(&pType, SC_REGISTER); + break; + case TOK_STATIC: + insertStorageClass(&pType, SC_STATIC); + break; + case TOK_EXTERN: + insertStorageClass(&pType, SC_EXTERN); + break; + case TOK_TYPEDEF: + insertStorageClass(&pType, SC_TYPEDEF); + break; + case TOK_INT: + insertTypeSpecifier(&pType, TY_INT); + break; + case TOK_SHORT: + insertTypeSpecifier(&pType, TY_SHORT); + break; + case TOK_CHAR: + insertTypeSpecifier(&pType, TY_CHAR); + break; + case TOK_VOID: + insertTypeSpecifier(&pType, TY_VOID); + break; + case TOK_FLOAT: + insertTypeSpecifier(&pType, TY_FLOAT); + break; + case TOK_DOUBLE: + insertTypeSpecifier(&pType, TY_DOUBLE); + break; + case TOK_STRUCT: + case TOK_UNION: + { + insertTypeSpecifier(&pType, TY_STRUCT); + bool isStruct = (tok == TOK_STRUCT); + next(); + pType = acceptStruct(pType, isStruct); + keepGoing = false; + } + break; + default: + // Is it a typedef? + if (isSymbol(tok)) { + VariableInfo* pV = VI(tok); + if (pV && pV->pType->storageClass == SC_TYPEDEF) { + if (! pType) { + pType = createType(TY_UNKNOWN, NULL, NULL); + } + StorageClass storageClass = pType->storageClass; + *pType = *pV->pType; + pType->storageClass = storageClass; + } else { + keepGoing = false; + } + } else { + keepGoing = false; + } + } + if (keepGoing) { + next(); + } + } + if (pType) { + if (pType->tag == TY_UNKNOWN) { + pType->tag = TY_INT; + } + if (allowStorageClass) { + switch(pType->storageClass) { + case SC_AUTO: error("auto not supported."); break; + case SC_REGISTER: error("register not supported."); break; + case SC_STATIC: error("static not supported."); break; + case SC_EXTERN: error("extern not supported."); break; + default: break; + } + } else { + if (pType->storageClass != SC_DEFAULT) { + error("An explicit storage class is not allowed in this type declaration"); + } + } } - next(); return pType; } - Type* acceptStruct() { - assert(tok == TOK_STRUCT || tok == TOK_UNION); - bool isStruct = tok == TOK_STRUCT; - next(); + Type* acceptStruct(Type* pStructType, bool isStruct) { 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; @@ -5327,9 +5425,11 @@ class Compiler : public ErrorSink { if (needToDeclare) { // This is a new struct name pToken->mpStructInfo = mpCurrentSymbolStack->addStructTag(structTag); + StorageClass storageClass = pStructType->storageClass; pStructType = createType(TY_STRUCT, NULL, NULL); pStructType->structTag = structTag; pStructType->pHead = pStructType; + pStructType->storageClass = storageClass; if (! isDeclaration) { // A forward declaration pStructType->length = -1; @@ -5347,7 +5447,7 @@ class Compiler : public ErrorSink { size_t structAlignment = 0; Type** pParamHolder = & pStructType->pHead->pTail; while (tok != '}' && tok != EOF) { - Type* pPrimitiveType = expectPrimitiveType(); + Type* pPrimitiveType = expectPrimitiveType(false); if (pPrimitiveType) { while (tok != ';' && tok != EOF) { Type* pItem = acceptDeclaration(pPrimitiveType, true, false); @@ -5410,6 +5510,7 @@ class Compiler : public ErrorSink { Type* acceptDeclaration(Type* pType, bool nameAllowed, bool nameRequired) { tokenid_t declName = 0; bool reportFailure = false; + StorageClass storageClass = pType->storageClass; pType = acceptDecl2(pType, declName, nameAllowed, nameRequired, reportFailure); if (declName) { @@ -5418,6 +5519,7 @@ class Compiler : public ErrorSink { pType = createType(pType->tag, pType->pHead, pType->pTail); *pType = *pOldType; pType->id = declName; + pType->storageClass = storageClass; } else if (nameRequired) { error("Expected a variable name"); } @@ -5442,7 +5544,7 @@ class Compiler : public ErrorSink { /* Used for accepting types that appear in casts */ Type* acceptCastTypeDeclaration() { - Type* pType = acceptPrimitiveType(); + Type* pType = acceptPrimitiveType(false); if (pType) { pType = acceptDeclaration(pType, false, false); } @@ -5530,7 +5632,7 @@ class Compiler : public ErrorSink { Type* pHead = NULL; Type* pTail = NULL; for(;;) { - Type* pBaseArg = acceptPrimitiveType(); + Type* pBaseArg = acceptPrimitiveType(false); if (pBaseArg) { Type* pArg = acceptDeclaration(pBaseArg, nameAllowed, false); if (pArg) { @@ -5551,8 +5653,8 @@ class Compiler : public ErrorSink { return pHead; } - Type* expectPrimitiveType() { - Type* pType = acceptPrimitiveType(); + Type* expectPrimitiveType(bool allowStorageClass) { + Type* pType = acceptPrimitiveType(allowStorageClass); if (!pType) { String buf; decodeToken(buf, tok, true); @@ -5620,7 +5722,7 @@ class Compiler : public ErrorSink { break; } // Else it's a forward declaration of a function. - } else { + } else if (pDecl->storageClass != SC_TYPEDEF) { int variableAddress = 0; size_t alignment = pGen->alignmentOf(pDecl); assert(alignment > 0); @@ -5645,7 +5747,7 @@ class Compiler : public ErrorSink { next(); } skip(';'); - pBaseType = acceptPrimitiveType(); + pBaseType = acceptPrimitiveType(true); } } @@ -5709,7 +5811,7 @@ class Compiler : public ErrorSink { void globalDeclarations() { mpCurrentSymbolStack = &mGlobals; while (tok != EOF) { - Type* pBaseType = expectPrimitiveType(); + Type* pBaseType = expectPrimitiveType(true); if (!pBaseType) { break; } @@ -5726,7 +5828,6 @@ class Compiler : public ErrorSink { skip(';'); continue; } - if (! isDefined(pDecl->id)) { addGlobalSymbol(pDecl); } @@ -5737,19 +5838,23 @@ class Compiler : public ErrorSink { if (pDecl->tag < TY_FUNC) { // it's a variable declaration for(;;) { - if (name && !name->pAddress) { - name->pAddress = (int*) allocGlobalSpace( - pGen->alignmentOf(name->pType), - pGen->sizeOf(name->pType)); - } - if (accept('=')) { - if (tok == TOK_NUM) { - if (name) { - * (int*) name->pAddress = tokc; + if (pDecl->storageClass == SC_TYPEDEF) { + // Do not allocate storage. + } else { + if (name && !name->pAddress) { + name->pAddress = (int*) allocGlobalSpace( + pGen->alignmentOf(name->pType), + pGen->sizeOf(name->pType)); + } + if (accept('=')) { + if (tok == TOK_NUM) { + if (name) { + * (int*) name->pAddress = tokc; + } + next(); + } else { + error("Expected an integer constant"); } - next(); - } else { - error("Expected an integer constant"); } } if (!accept(',')) { diff --git a/libacc/tests/data/typedef.c b/libacc/tests/data/typedef.c new file mode 100644 index 000000000..c392f6a30 --- /dev/null +++ b/libacc/tests/data/typedef.c @@ -0,0 +1,40 @@ +typedef short COORD; +typedef struct Point { + COORD x; + COORD y; +} Point; + +void add(Point* result, Point* a, Point* b) { + result->x = a->x + b->x; + result->y = a->y + b->y; +} + +void print(Point* p) { + printf("(%d, %d)", p->x, p->y); +} + +void set(Point* p, int x, int y) { + p->x = x; + p->y = y; +} + +int main() { + typedef char* String; + String s = "x = %d\n"; + { + typedef int item; + item x = 3; + printf(s, x); + } + Point a, b, c; + set(&a, 1,2); + set(&b, 3,4); + add(&c, &a, &b); + print(&c); + printf(" = "); + print(&a); + printf(" + "); + print(&b); + printf("\n"); + return 0; +} diff --git a/libacc/tests/test.py b/libacc/tests/test.py index 8f4920b89..6e0899cd8 100644 --- a/libacc/tests/test.py +++ b/libacc/tests/test.py @@ -311,6 +311,12 @@ Testing read/write (double*): 8.8 9.9 result: 0""", """a = 99, b = 41 ga = 100, gb = 44""") + def testTypedef(self): + self.compileCheck(["-R", "data/typedef.c"], """Executing compiled code: +result: 0""", """x = 3 +(4, 6) = (1, 2) + (3, 4) +""") + def testPointerArithmetic(self): self.compileCheck(["-R", "data/pointers.c"], """Executing compiled code: result: 0""", """Pointer difference: 1 4