Loading libacc/FEATURES +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading libacc/acc.cpp +151 −46 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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"); } } } 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; Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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"); } Loading @@ -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); } Loading Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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); Loading @@ -5645,7 +5747,7 @@ class Compiler : public ErrorSink { next(); } skip(';'); pBaseType = acceptPrimitiveType(); pBaseType = acceptPrimitiveType(true); } } Loading Loading @@ -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; } Loading @@ -5726,7 +5828,6 @@ class Compiler : public ErrorSink { skip(';'); continue; } if (! isDefined(pDecl->id)) { addGlobalSymbol(pDecl); } Loading @@ -5737,6 +5838,9 @@ class Compiler : public ErrorSink { if (pDecl->tag < TY_FUNC) { // it's a variable declaration for(;;) { if (pDecl->storageClass == SC_TYPEDEF) { // Do not allocate storage. } else { if (name && !name->pAddress) { name->pAddress = (int*) allocGlobalSpace( pGen->alignmentOf(name->pType), Loading @@ -5752,6 +5856,7 @@ class Compiler : public ErrorSink { error("Expected an integer constant"); } } } if (!accept(',')) { break; } Loading libacc/tests/data/typedef.c 0 → 100644 +40 −0 Original line number Diff line number Diff line 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; } libacc/tests/test.py +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
libacc/FEATURES +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
libacc/acc.cpp +151 −46 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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"); } } } 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; Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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"); } Loading @@ -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); } Loading Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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); Loading @@ -5645,7 +5747,7 @@ class Compiler : public ErrorSink { next(); } skip(';'); pBaseType = acceptPrimitiveType(); pBaseType = acceptPrimitiveType(true); } } Loading Loading @@ -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; } Loading @@ -5726,7 +5828,6 @@ class Compiler : public ErrorSink { skip(';'); continue; } if (! isDefined(pDecl->id)) { addGlobalSymbol(pDecl); } Loading @@ -5737,6 +5838,9 @@ class Compiler : public ErrorSink { if (pDecl->tag < TY_FUNC) { // it's a variable declaration for(;;) { if (pDecl->storageClass == SC_TYPEDEF) { // Do not allocate storage. } else { if (name && !name->pAddress) { name->pAddress = (int*) allocGlobalSpace( pGen->alignmentOf(name->pType), Loading @@ -5752,6 +5856,7 @@ class Compiler : public ErrorSink { error("Expected an integer constant"); } } } if (!accept(',')) { break; } Loading
libacc/tests/data/typedef.c 0 → 100644 +40 −0 Original line number Diff line number Diff line 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; }
libacc/tests/test.py +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading