Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee1f829d authored by Jack Palevich's avatar Jack Palevich
Browse files

Implement typedef.

parent 22f5c6b8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+151 −46
Original line number Diff line number Diff line
@@ -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");
                }
            }
        }
        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,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),
@@ -5752,6 +5856,7 @@ class Compiler : public ErrorSink {
                                error("Expected an integer constant");
                            }
                        }
                    }
                    if (!accept(',')) {
                        break;
                    }
+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;
}
+6 −0
Original line number Diff line number Diff line
@@ -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