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

Commit 8635198c authored by Jack Palevich's avatar Jack Palevich
Browse files

Add a type system.

We now track the declared type of variables and functions.
parent 569f1358
Loading
Loading
Loading
Loading
+265 −103
Original line number Diff line number Diff line
@@ -1492,8 +1492,6 @@ class Compiler : public ErrorSink {
                probe.pText = (char*) pText;
                Token* pValue = (Token*) hashmapGet(mpMap, &probe);
                if (pValue) {
                    // printf("intern - found existing %s for %d\n",
                    // pValue->pText, pValue->id);
                    return pValue->id;
                }
            }
@@ -1508,7 +1506,6 @@ class Compiler : public ErrorSink {
            pToken->id = mTokens.size() + TOKEN_BASE;
            mTokens.push_back(pToken);
            hashmapPut(mpMap, pToken, pToken);
            // printf("intern - new token %s %d\n", pToken->pText, pToken->id);
            return pToken->id;
        }

@@ -1657,6 +1654,10 @@ class Compiler : public ErrorSink {
            * ensure(1) = c;
        }

        void append(String& other) {
            appendBytes(other.getUnwrapped(), other.len());
        }

        char* orphan() {
            char* result = mpBase;
            mpBase = 0;
@@ -1759,12 +1760,15 @@ class Compiler : public ErrorSink {
        int oldCh;
    };

    struct Type;

    struct VariableInfo {
        void* pAddress;
        void* pForward; // For a forward direction, linked list of data to fix up
        tokenid_t tok;
        size_t level;
        VariableInfo* pOldDefinition;
        Type* pType;
    };

    class SymbolStack {
@@ -1820,6 +1824,12 @@ class Compiler : public ErrorSink {
            return pNewV;
        }

        VariableInfo* add(Type* pType) {
            VariableInfo* pVI = add(pType->id);
            pVI->pType = pType;
            return pVI;
        }

        void forEach(bool (*fn)(VariableInfo*, void*), void* context) {
            for (size_t i = 0; i < mStack.size(); i++) {
                if (! fn(mStack[i], context)) {
@@ -1865,6 +1875,10 @@ class Compiler : public ErrorSink {
    SymbolStack mGlobals;
    SymbolStack mLocals;

    Type* mkpInt;
    Type* mkpChar;
    Type* mkpVoid;

    InputStream* file;

    CodeBuf codeBuf;
@@ -1975,11 +1989,16 @@ class Compiler : public ErrorSink {
        * (char*) 0 = 0;
    }

    void assert(bool isTrue) {
        if (!isTrue) {
            internalError();
        }
    }

    VariableInfo* VI(tokenid_t t) {
        if ( t < TOK_SYMBOL || t-TOK_SYMBOL >= mTokenTable.size()) {
        if ( t < TOK_SYMBOL || ((size_t) (t-TOK_SYMBOL)) >= mTokenTable.size()) {
            internalError();
        }
        // printf("Looking up %s %d\n", nameof(t), t);
        VariableInfo* pV = mTokenTable[t].mpVariableInfo;
        if (pV && pV->tok != t) {
            internalError();
@@ -2209,7 +2228,8 @@ class Compiler : public ErrorSink {
        {
            String buf;
            decodeToken(buf, tok);
            printf("%s\n", buf.getUnwrapped());        }
            fprintf(stderr, "%s\n", buf.getUnwrapped());
        }
#endif
    }

@@ -2296,6 +2316,14 @@ class Compiler : public ErrorSink {
        next();
    }

    bool accept(intptr_t c) {
        if (tok == c) {
            next();
            return true;
        }
        return false;
    }

    /* l is one if '=' parsing wanted (quick hack) */
    void unary(intptr_t l) {
        intptr_t n, t, a;
@@ -2553,105 +2581,223 @@ class Compiler : public ErrorSink {
        }
    }

    typedef int Type;
    static const Type TY_UNKNOWN = 0;
    static const Type TY_INT = 1;
    static const Type TY_CHAR = 2;
    static const Type TY_VOID = 3;
    static const int TY_BASE_TYPE_MASK = 0xf;
    static const int TY_INDIRECTION_MASK = 0xf0;
    static const int TY_INDIRECTION_SHIFT = 4;
    static const int MAX_INDIRECTION_COUNT = 15;
    enum TypeTag {
        TY_INT, TY_CHAR, TY_VOID, TY_POINTER, TY_FUNC, TY_PARAM
    };

    Type getBaseType(Type t) {
        return t & TY_BASE_TYPE_MASK;
    struct Type {
        TypeTag tag;
        tokenid_t id; // For function arguments
        Type* pHead;
        Type* pTail;
    };

    Type* createType(TypeTag tag, Type* pHead, Type* pTail, Arena& arena) {
        assert(tag >= TY_INT && tag <= TY_PARAM);
        Type* pType = (Type*) arena.alloc(sizeof(Type));
        memset(pType, 0, sizeof(*pType));
        pType->tag = tag;
        pType->pHead = pHead;
        pType->pTail = pTail;
        return pType;
    }

    int getIndirectionCount(Type t) {
        return (TY_INDIRECTION_MASK & t) >> TY_INDIRECTION_SHIFT;
    void decodeType(String& buffer, Type* pType) {
        if (pType == NULL) {
            buffer.appendCStr("null");
            return;
        }
        buffer.append('(');
        String temp;
        if (pType->id != 0) {
            decodeToken(temp, pType->id);
            buffer.append(temp);
            buffer.append(' ');
        }
        bool printHead = false;
        bool printTail = false;
        switch (pType->tag) {
            case TY_INT:
                buffer.appendCStr("int");
                break;
            case TY_CHAR:
                buffer.appendCStr("char");
                break;
            case TY_VOID:
                buffer.appendCStr("void");
                break;
            case TY_POINTER:
                buffer.appendCStr("*");
                printHead = true;
                break;
            case TY_FUNC:
                buffer.appendCStr("func");
                printHead = true;
                printTail = true;
                break;
            case TY_PARAM:
                buffer.appendCStr("param");
                printHead = true;
                printTail = true;
                break;
            default:
                String temp;
                temp.printf("Unknown tag %d", pType->tag);
                buffer.append(temp);
                break;
        }
        if (printHead) {
            buffer.append(' ');
            decodeType(buffer, pType->pHead);
        }
        if (printTail) {
            buffer.append(' ');
            decodeType(buffer, pType->pTail);
        }
        buffer.append(')');
    }

    void setIndirectionCount(Type& t, int count) {
        t = ((TY_INDIRECTION_MASK & (count << TY_INDIRECTION_SHIFT))
                | (t & ~TY_INDIRECTION_MASK));
    void printType(Type* pType) {
        String buffer;
        decodeType(buffer, pType);
        fprintf(stderr, "%s\n", buffer.getUnwrapped());
    }

    bool acceptType(Type& t) {
        t = TY_UNKNOWN;
    Type* acceptPrimitiveType(Arena& arena) {
        Type* pType;
        if (tok == TOK_INT) {
            t = TY_INT;
            pType = mkpInt;
        } else if (tok == TOK_CHAR) {
            t = TY_CHAR;
            pType = mkpChar;
        } else if (tok == TOK_VOID) {
            t = TY_VOID;
            pType = mkpVoid;
        } else {
            return false;
            return NULL;
        }
        next();
        return true;
        return pType;
    }

    Type acceptPointerDeclaration(Type& base) {
        Type t = base;
        int indirectionCount = 0;
        while (tok == '*' && indirectionCount <= MAX_INDIRECTION_COUNT) {
    Type* acceptDeclaration(const Type* pBaseType, Arena& arena) {
        Type* pType = createType(pBaseType->tag, pBaseType->pHead,
                                 pBaseType->pTail, arena);
        tokenid_t declName;
        if (pType) {
            pType = acceptDecl2(pType, declName, arena);
            pType->id = declName;
            // fprintf(stderr, "Parsed a declaration:       ");
            // printType(pType);
        }
        return pType;
    }

    Type* expectDeclaration(const Type* pBaseType, Arena& arena) {
        Type* pType = acceptDeclaration(pBaseType, arena);
        if (! pType) {
            error("Expected a declaration");
        }
        return pType;
    }

    Type* acceptDecl2(Type* pType, tokenid_t& declName, Arena& arena) {
        while (tok == '*') {
            pType = createType(TY_POINTER, pType, NULL, arena);
            next();
            indirectionCount++;
        }
        if (indirectionCount > MAX_INDIRECTION_COUNT) {
            error("Too many levels of pointer. Max %d", MAX_INDIRECTION_COUNT);
        pType = acceptDecl3(pType, declName, arena);
        return pType;
    }
        setIndirectionCount(t, indirectionCount);
        return t;

    Type* acceptDecl3(Type* pType, tokenid_t& declName, Arena& arena) {
        if (accept('(')) {
            pType = acceptDecl2(pType, declName, arena);
            skip(')');
        } else {
            declName = acceptSymbol();
        }
        while (tok == '(') {
            // Function declaration
            skip('(');
            Type* pTail = acceptArgs(arena);
            pType = createType(TY_FUNC, pType, pTail, arena);
            skip(')');
        }
        return pType;
    }

    void expectType(Type& t) {
        if (!acceptType(t)) {
    Type* acceptArgs(Arena& arena) {
        Type* pHead = NULL;
        Type* pTail = NULL;
        for(;;) {
            Type* pBaseArg = acceptPrimitiveType(arena);
            if (pBaseArg) {
                Type* pArg = acceptDeclaration(pBaseArg, arena);
                if (pArg) {
                    Type* pParam = createType(TY_PARAM, pArg, NULL, arena);
                    if (!pHead) {
                        pHead = pParam;
                        pTail = pParam;
                    } else {
                        pTail->pTail = pParam;
                        pTail = pParam;
                    }
                }
            }
            if (! accept(',')) {
                break;
            }
        }
        return pHead;
    }

    Type* expectPrimitiveType(Arena& arena) {
        Type* pType = acceptPrimitiveType(arena);
        if (!pType) {
            String buf;
            decodeToken(buf, tok);
            error("Expected a type, got %s", buf.getUnwrapped());
        }
        return pType;
    }

    void addGlobalSymbol() {
        VariableInfo* pVI = VI(tok);
    void addGlobalSymbol(Type* pDecl) {
        tokenid_t t = pDecl->id;
        VariableInfo* pVI = VI(t);
        if(pVI && pVI->pAddress) {
            reportDuplicate();
            reportDuplicate(t);
        }
        mGlobals.add(tok);
        mGlobals.add(pDecl);
    }

    void reportDuplicate() {
        error("Duplicate definition of %s", nameof(tok));
    void reportDuplicate(tokenid_t t) {
        error("Duplicate definition of %s", nameof(t));
    }

    void addLocalSymbol() {
        if (mLocals.isDefinedAtCurrentLevel(tok)) {
            reportDuplicate();
    void addLocalSymbol(Type* pDecl) {
        tokenid_t t = pDecl->id;
        if (mLocals.isDefinedAtCurrentLevel(t)) {
            reportDuplicate(t);
        }
        mLocals.add(tok);
        mLocals.add(pDecl);
    }

    void localDeclarations() {
        intptr_t a;
        Type base;
        Type* pBaseType;

        while (acceptType(base)) {
        while ((pBaseType = acceptPrimitiveType(mLocalArena)) != NULL) {
            while (tok != ';' && tok != EOF) {
                Type t = acceptPointerDeclaration(t);
                Type* pDecl = expectDeclaration(pBaseType, mLocalArena);
                if (!pDecl) {
                    break;
                }
                int variableAddress = 0;
                if (checkSymbol()) {
                    addLocalSymbol();
                    if (tok) {
                addLocalSymbol(pDecl);
                loc = loc + 4;
                variableAddress = -loc;
                        VI(tok)->pAddress = (void*) variableAddress;
                    }
                }
                next();
                if (tok == '=') {
                VI(pDecl->id)->pAddress = (void*) variableAddress;
                if (accept('=')) {
                    /* assignment */
                    next();
                    expr();
                    pGen->storeR0(variableAddress);
                }
@@ -2672,7 +2818,11 @@ class Compiler : public ErrorSink {
        } else if (token == TOK_NUM) {
            buffer.printf("numeric constant");
        } else if (token >= 0 && token < 256) {
            buffer.printf("char \'%c\'", token);
            if (token < 32) {
                buffer.printf("'\\x%02x'", token);
            } else {
                buffer.printf("'%c'", token);
            }
        } else if (token >= TOK_KEYWORD && token < TOK_SYMBOL) {
            buffer.printf("keyword \"%s\"", nameof(token));
        } else {
@@ -2690,32 +2840,43 @@ class Compiler : public ErrorSink {
        return result;
    }

    tokenid_t acceptSymbol() {
        tokenid_t result = 0;
        if (tok >= TOK_SYMBOL) {
            result = tok;
            next();
        } else {
            String temp;
            decodeToken(temp, tok);
            error("Expected symbol. Got %s", temp.getUnwrapped());
        }
        return result;
    }

    void globalDeclarations() {
        while (tok != EOF) {
            Type base;
            expectType(base);
            Type t = acceptPointerDeclaration(t);
            if (tok < TOK_SYMBOL) {
                error("Unexpected token %d", tok);
            Type* pBaseType = expectPrimitiveType(mGlobalArena);
            if (!pBaseType) {
                break;
            }
            if (! isDefined(tok)) {
                addGlobalSymbol();
            Type* pDecl = expectDeclaration(pBaseType, mGlobalArena);
            if (!pDecl) {
                break;
            }
            if (! isDefined(pDecl->id)) {
                addGlobalSymbol(pDecl);
            }
            VariableInfo* name = VI(tok);
            VariableInfo* name = VI(pDecl->id);
            if (name && name->pAddress) {
                error("Already defined global %s",
                      mTokenString.getUnwrapped());
                error("Already defined global %s", nameof(pDecl->id));
            }
            next();
            if (tok == ',' || tok == ';' || tok == '=') {
            if (pDecl->tag < TY_FUNC) {
                // it's a variable declaration
                for(;;) {
                    if (name) {
                    if (name && !name->pAddress) {
                        name->pAddress = (int*) allocGlobalSpace(4);
                    }
                    if (tok == '=') {
                        next();
                    if (accept('=')) {
                        if (tok == TOK_NUM) {
                            if (name) {
                                * (int*) name->pAddress = tokc;
@@ -2725,17 +2886,21 @@ class Compiler : public ErrorSink {
                            error("Expected an integer constant");
                        }
                    }
                    if (tok != ',') {
                    if (!accept(',')) {
                        break;
                    }
                    skip(',');
                    t = acceptPointerDeclaration(t);
                    addGlobalSymbol();
                    name = VI(tok);
                    next();
                    pDecl = expectDeclaration(pBaseType, mGlobalArena);
                    if (!pDecl) {
                        break;
                    }
                    if (! isDefined(pDecl->id)) {
                        addGlobalSymbol(pDecl);
                    }
                    name = VI(pDecl->id);
                }
                skip(';');
            } else {
                // Function declaration
                if (name) {
                    /* patch forward references (XXX: does not work for function
                     pointers) */
@@ -2743,28 +2908,18 @@ class Compiler : public ErrorSink {
                    /* put function address */
                    name->pAddress = (void*) codeBuf.getPC();
                }
                skip('(');
                // Calculate stack offsets for parameters
                mLocals.pushLevel();
                intptr_t a = 8;
                int argCount = 0;
                while (tok != ')' && tok != EOF) {
                    Type aType;
                    expectType(aType);
                    aType = acceptPointerDeclaration(aType);
                    if (checkSymbol()) {
                        addLocalSymbol();
                        if (tok) {
                for (Type* pP = pDecl->pTail; pP; pP = pP->pTail) {
                    Type* pArg = pP->pHead;
                    addLocalSymbol(pArg);
                    /* read param name and compute offset */
                            VI(tok)->pAddress = (void*) a;
                    VI(pArg->id)->pAddress = (void*) a;
                    a = a + 4;
                        }
                    }
                    next();
                    if (tok == ',')
                        next();
                    argCount++;
                }
                skip(')');
                rsym = loc = 0;
                a = pGen->functionEntry(argCount);
                block(0, true);
@@ -2878,6 +3033,7 @@ public:
        mLocals.setTokenTable(&mTokenTable);

        internKeywords();
        createPrimitiveTypes();
        codeBuf.init(ALLOC_SIZE);
        setArchitecture(NULL);
        if (!pGen) {
@@ -2904,6 +3060,12 @@ public:
        return result;
    }

    void createPrimitiveTypes() {
        mkpInt = createType(TY_INT, NULL, NULL, mGlobalArena);
        mkpChar = createType(TY_CHAR, NULL, NULL, mGlobalArena);
        mkpVoid = createType(TY_VOID, NULL, NULL, mGlobalArena);
    }

    void checkForUndefinedForwardReferences() {
        mGlobals.forEach(static_ufrcFn, this);
    }