Implement typedef.
This commit is contained in:
parent
22f5c6b8a2
commit
ee1f829dd4
4 changed files with 199 additions and 46 deletions
|
|
@ -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
|
||||
|
|
|
|||
197
libacc/acc.cpp
197
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(',')) {
|
||||
|
|
|
|||
40
libacc/tests/data/typedef.c
Normal file
40
libacc/tests/data/typedef.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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…
Add table
Reference in a new issue