Implement typedef.

This commit is contained in:
Jack Palevich 2009-10-28 16:10:17 -07:00
parent 22f5c6b8a2
commit ee1f829dd4
4 changed files with 199 additions and 46 deletions

View file

@ -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

View file

@ -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(',')) {

View 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;
}

View file

@ -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