Beispiel #1
1
/**
 * ParamList = "(" [ ( Param [{ "," Param }] [ "," "..." ] ) | "..." | "void" ] ")"
 */
void parserParamList (parserCtx* ctx, ast* Node, bool inDecl) {
    debugEnter("ParamList");

    tokenMatchPunct(ctx, punctLParen);

    if (!tokenIsPunct(ctx, punctRParen)) {
        tokenLocation voidloc = ctx->location;

        bool end = false;

        /*Either an empty prototype declaration,
          or the beginning of a void* parameter*/
        if (tokenTryMatchKeyword(ctx, keywordVoid)) {
            if (!tokenIsPunct(ctx, punctRParen)) {
                ast* basic = astCreateLiteralIdent(voidloc, strdup("void"));
                ast* expr = parserDeclExpr(ctx, inDecl, symParam);
                ast* param = astCreateParam(voidloc, basic, expr);
                param->symbol = basic->symbol = symFind(ctx->scope, "void");
                astAddChild(Node, param);

                if (!tokenTryMatchPunct(ctx, punctComma))
                    end = true;

            } else
                end = true;
        }

        if (!end) do {
            if (tokenIsPunct(ctx, punctEllipsis)) {
                astAddChild(Node, astCreate(astEllipsis, ctx->location));
                tokenMatch(ctx);
                break;

            } else
                astAddChild(Node, parserParam(ctx, inDecl));

        } while (tokenTryMatchPunct(ctx, punctComma));
    }

    tokenMatchPunct(ctx, punctRParen);

    debugLeave();
}
Beispiel #2
0
/**
 * FnImpl = Code
 */
static ast* parserFnImpl (parserCtx* ctx, ast* decl) {
    debugEnter("FnImpl");

    sym* fn = decl->firstChild->symbol;

    ast* Node = astCreateFnImpl(ctx->location, decl);
    Node->symbol = fn;

    /*Is a function implementation valid for this symbol?*/

    if (fn->impl)
        errorReimplementedSym(ctx, fn);

    else {
        fn->impl = Node;
        /*Now that we have the implementation, create param symbols*/
        parserCreateParamSymbols(decl->firstChild, fn);
    }

    /*Body*/

    sym* OldScope = scopeSet(ctx, fn);
    Node->r = parserCode(ctx);
    ctx->scope = OldScope;

    debugLeave();

    return Node;
}
Beispiel #3
0
type* analyzerParamList (analyzerCtx* ctx, ast* Node, type* returnType) {
    debugEnter("ParamList");

    bool variadic = false;
    type** paramTypes = calloc(Node->children, sizeof(type*));
    int paramNo = 0;

    for (ast* param = Node->firstChild;
         param;
         param = param->nextSibling) {
        /*Ellipsis to indicate variadic function. The grammar has already
          ensured there is only one and that it is the final parameter.*/
        if (param->tag == astEllipsis) {
            variadic = true;
            debugMsg("Ellipsis");

        } else if (param->tag == astParam) {
            const type* BasicDT = analyzerDeclBasic(ctx, param->l);
            const type* paramType = analyzerDeclNode(ctx, param->r, typeDeepDuplicate(BasicDT), false, storageUndefined);

            paramTypes[paramNo++] = typeDeepDuplicate(paramType);

            if (!typeIsComplete(paramType))
                errorIncompleteParamDecl(ctx, param, Node, paramNo, paramType);

        } else
            debugErrorUnhandled("analyzerParamList", "AST tag", astTagGetStr(param->tag));
    }

    type* DT = typeCreateFunction(returnType, paramTypes, paramNo, variadic);

    debugLeave();

    return DT;
}
Beispiel #4
0
/**
 * DeclAtom = [ ( "(" DeclExpr ")" ) | Name ]
 *
 * This is where the inDecl/tag stuff we've been keeping track of
 * comes into play. If outside a declaration, idents are not allowed.
 * Inside a declaration, an ident is *required* unless in the parameters,
 * where they are optional (even outside a prototype...).
 */
static ast* parserDeclAtom (parserCtx* ctx, bool inDecl, symTag tag) {
    debugEnter("DeclAtom");

    ast* Node;

    if (tokenTryMatchPunct(ctx, punctLParen)) {
        Node = parserDeclExpr(ctx, inDecl, tag);
        tokenMatchPunct(ctx, punctRParen);

    } else if (tokenIsIdent(ctx)) {
        if (inDecl || tag == symParam)
            Node = parserName(ctx, inDecl, tag);

        else {
            Node = astCreateInvalid(ctx->location);
            errorIllegalOutside(ctx, "identifier", "a declaration");
            tokenNext(ctx);
        }

    } else if (inDecl && tag != symParam)
        Node = parserName(ctx, inDecl, tag);

    else
        Node = astCreateEmpty(ctx->location);

    debugLeave();

    return Node;
}
Beispiel #5
0
static const type* analyzerDeclNode (analyzerCtx* ctx, ast* Node, type* base, bool module, storageTag storage) {
    debugEnter(astTagGetStr(Node->tag));

    const type* DT = 0;

    if (Node->tag == astInvalid || Node->tag == astEmpty)
        ;

    else if (Node->tag == astBOP) {
        if (Node->o == opAssign)
            DT = analyzerDeclAssignBOP(ctx, Node, base, module, storage);

        else
            debugErrorUnhandled("analyzerDeclNode", "operator", opTagGetStr(Node->o));

    } else if (Node->tag == astUOP) {
        if (Node->o == opDeref)
            DT = analyzerDeclPtrUOP(ctx, Node, base, module, storage);

        else
            debugErrorUnhandled("analyzerDeclNode", "operator", opTagGetStr(Node->o));

    } else if (Node->tag == astLiteral) {
        if (Node->litTag == literalIdent)
            DT = analyzerDeclIdentLiteral(ctx, Node, base, module, storage);

        else
            debugErrorUnhandled("analyzerDeclNode", "literal tag", literalTagGetStr(Node->litTag));

    } else if (Node->tag == astConst)
        DT = analyzerConst(ctx, Node, base, module, storage);

    else if (Node->tag == astCall)
        DT = analyzerDeclCall(ctx, Node, base, module, storage);

    else if (Node->tag == astIndex)
        DT = analyzerDeclIndex(ctx, Node, base, module, storage);

    else
        debugErrorUnhandled("analyzerDeclNode", "AST tag", astTagGetStr(Node->tag));

    /*Assign type for error states*/

    if (Node->symbol && !Node->symbol->dt)
        Node->symbol->dt = base;

    else if (!DT)
        Node->dt = base;

    if (!DT)
        DT = base;

    debugLeave();

    return DT;
}
Beispiel #6
0
const type* analyzerType (analyzerCtx* ctx, ast* Node) {
    debugEnter("Type");

    const type* BasicDT = analyzerDeclBasic(ctx, Node->l);
    Node->dt = typeDeepDuplicate(analyzerDeclNode(ctx, Node->r, typeDeepDuplicate(BasicDT), false, storageUndefined));

    debugLeave();

    return Node->dt;
}
Beispiel #7
0
/**
 * StructOrUnion = "struct" | "union" Name# ^ ( "{" [{ Field }] "}" )
 *
 * Name is told to create a symbol of the tag indicated by the first
 * token.
 */
static struct ast* parserStructOrUnion (parserCtx* ctx) {
    debugEnter("StructOrUnion");

    tokenLocation loc = ctx->location;

    symTag tag =   tokenTryMatchKeyword(ctx, keywordStruct)
                 ? symStruct
                 : (tokenMatchKeyword(ctx, keywordUnion), symUnion);

    ast* name;

    /*Name*/

    if (tokenIsIdent(ctx))
        name = parserName(ctx, true, tag);

    /*Anonymous struct, will require a body*/
    else {
        name = astCreateEmpty(loc);
        name->literal = strdup("");
        name->symbol = symCreateNamed(tag, ctx->scope, "");
    }

    ast* Node = (tag == symStruct ? astCreateStruct : astCreateUnion)
                (loc, name);
    Node->symbol = Node->l->symbol;
    sym* OldScope = scopeSet(ctx, Node->symbol);

    /*Body*/
    if (Node->l->tag == astEmpty || tokenIsPunct(ctx, punctLBrace)) {
        /*Only error if not already errored for wrong tag*/
        if (Node->symbol->impl && Node->symbol->tag == tag)
            errorReimplementedSym(ctx, Node->symbol);

        else
            Node->symbol->impl = Node;

        tokenMatchPunct(ctx, punctLBrace);

        Node->symbol->complete = true;

        /*Eat fields*/
        while (!tokenIsPunct(ctx, punctRBrace))
            astAddChild(Node, parserField(ctx));

        tokenMatchPunct(ctx, punctRBrace);
    }

    ctx->scope = OldScope;

    debugLeave();

    return Node;
}
Beispiel #8
0
/**
 * Type = DeclBasic DeclExpr#
 *
 * DeclExpr is told not to allow identifiers or initiations, and not
 * to create symbols.
 */
 ast* parserType (parserCtx* ctx) {
    debugEnter("Type");

    tokenLocation loc = ctx->location;
    ast* basic = parserDeclBasic(ctx);
    ast* expr = parserDeclExpr(ctx, false, symUndefined);
    ast* Node = astCreateType(loc, basic, expr);

    debugLeave();

    return Node;
}
Beispiel #9
0
/**
 * Param = DeclBasic DeclExpr#
 *
 * DeclExpr is told to accept but not require identifiers and symbol
 * creation if and only if inDecl is true.
 */
static ast* parserParam (parserCtx* ctx, bool inDecl) {
    debugEnter("Param");

    tokenLocation loc = ctx->location;
    ast* basic = parserDeclBasic(ctx);
    ast* expr = parserDeclExpr(ctx, inDecl, symParam);
    ast* Node = astCreateParam(loc, basic, expr);
    Node->symbol = Node->r->symbol;

    debugLeave();

    return Node;
}
Beispiel #10
0
/**
 * EnumField = Name# [ "=" AssignValue ]
 */
static ast* parserEnumField (parserCtx* ctx) {
    debugEnter("EnumField");

    ast* Node = parserName(ctx, true, symEnumConstant);
    tokenLocation loc = ctx->location;

    if (tokenTryMatchPunct(ctx, punctAssign)) {
        Node = astCreateBOP(loc, Node, opAssign, parserAssignValue(ctx));
        Node->symbol = Node->l->symbol;
    }

    debugLeave();

    return Node;
}
Beispiel #11
0
void analyzerNode (analyzerCtx* ctx, ast* Node) {
    debugEnter(astTagGetStr(Node->tag));

    if (Node->tag == astEmpty)
        debugMsg("Empty");

    else if (Node->tag == astInvalid)
        debugMsg("Invalid");

    else if (Node->tag == astModule)
        analyzerModule(ctx, Node);

    else if (Node->tag == astUsing)
        analyzerUsing(ctx, Node);

    else if (Node->tag == astFnImpl)
        analyzerFnImpl(ctx, Node);

    else if (Node->tag == astDecl)
        analyzerDecl(ctx, Node, false);

    else if (Node->tag == astCode)
        analyzerCode(ctx, Node);

    else if (Node->tag == astBranch)
        analyzerBranch(ctx, Node);

    else if (Node->tag == astLoop)
        analyzerLoop(ctx, Node);

    else if (Node->tag == astIter)
        analyzerIter(ctx, Node);

    else if (Node->tag == astReturn)
        analyzerReturn(ctx, Node);

    else if (Node->tag == astBreak || Node->tag == astContinue)
        ; /*Nothing to check (inside loop is a parsing issue)*/

    else if (astIsValueTag(Node->tag))
        /*TODO: Check not throwing away value*/
        analyzerValue(ctx, Node);

    else
        debugErrorUnhandled("analyzerNode", "AST tag", astTagGetStr(Node->tag));

    debugLeave();
}
Beispiel #12
0
/**
 * Field = DeclBasic [ DeclExpr# [{ "," DeclExpr# }] ] ";"
 *
 * DeclExpr is told to require idents and create symbols.
 */
static ast* parserField (parserCtx* ctx) {
    debugEnter("Field");

    tokenLocation loc = ctx->location;
    ast* Node = astCreateDecl(loc, parserDeclBasic(ctx));

    if (!tokenIsPunct(ctx, punctSemicolon)) do {
        astAddChild(Node, parserDeclExpr(ctx, true, symId));
    } while (tokenTryMatchPunct(ctx, punctComma));

    tokenMatchPunct(ctx, punctSemicolon);

    debugLeave();

    return Node;
}
Beispiel #13
0
/**
 * Enum = "enum" Name# ^ ( "{" EnumField [{ "," EnumField }] [ "," ] "}" )
 */
static struct ast* parserEnum (parserCtx* ctx) {
    debugEnter("Enum");

    tokenLocation loc = ctx->location;
    tokenMatchKeyword(ctx, keywordEnum);

    /*Name*/

    ast* name;

    if (tokenIsIdent(ctx))
        name = parserName(ctx, true, symEnum);

    else {
        name = astCreateEmpty(loc);
        name->literal = strdup("");
        name->symbol = symCreateNamed(symEnum, ctx->scope, "");
    }

    ast* Node = astCreateEnum(loc, name);
    Node->symbol = Node->l->symbol;
    Node->symbol->complete = true;

    /*Body*/
    if (Node->l->tag == astEmpty || tokenIsPunct(ctx, punctLBrace)) {
        /*Only error if not already errored for wrong tag*/
        if (Node->symbol->impl && Node->symbol->tag == symEnum)
            errorReimplementedSym(ctx, Node->symbol);

        else
            Node->symbol->impl = Node;

        tokenMatchPunct(ctx, punctLBrace);

        if (!tokenIsPunct(ctx, punctRBrace)) do {
            astAddChild(Node, parserEnumField(ctx));
        } while (tokenTryMatchPunct(ctx, punctComma) && !tokenIsPunct(ctx, punctRBrace));

        tokenMatchPunct(ctx, punctRBrace);
    }

    debugLeave();

    return Node;
}
Beispiel #14
0
/**
 * DeclObject = DeclAtom [{ ParamList | ( "[" Value "]" ) }]
 */
static ast* parserDeclObject (parserCtx* ctx, bool inDecl, symTag tag) {
    debugEnter("DeclObject");

    tokenLocation loc = ctx->location;
    ast* Node = parserDeclAtom(ctx, inDecl, tag);

    while (true) {
        sym* Symbol = Node->symbol;

        /*Function*/
        if (tokenIsPunct(ctx, punctLParen)) {
            /*The proper param symbols are created just before the parsing of the body,
              prototype params go in the bin, but exist for diagnostics*/
            sym* OldScope = scopeSet(ctx, symCreateScope(ctx->scope));

            Node = astCreateCall(loc, Node);
            parserParamList(ctx, Node, inDecl);

            ctx->scope = OldScope;

        /*Array*/
        } else if (tokenTryMatchPunct(ctx, punctLBracket)) {
            if (tokenIsPunct(ctx, punctRBracket))
                /*An empty [] is a synonym for * when in params*/
                Node =   tag == symParam
                       ? astCreateUOP(loc, opDeref, Node)
                       : astCreateIndex(loc, Node, astCreateEmpty(ctx->location));

            else
                Node = astCreateIndex(loc, Node, parserValue(ctx));

            tokenMatchPunct(ctx, punctRBracket);

        } else
            break;

        /*Propogate the declared symbol up the chain*/
        Node->symbol = Symbol;
    }

    debugLeave();

    return Node;
}
Beispiel #15
0
/**
 * DeclExpr = DeclUnary [ "=" AssignValue ]
 *
 * This uses AssignValue instead of Value, skipping comma operators.
 * This is to avoid the case of
 *     int x = 5, y = 6;
 * which would be parsed as
 *     int x = (5, y = 6);
 */
static ast* parserDeclExpr (parserCtx* ctx, bool inDecl, symTag tag) {
    debugEnter("DeclExpr");

    ast* Node = parserDeclUnary(ctx, inDecl, tag);
    tokenLocation loc = ctx->location;

    if (tokenTryMatchPunct(ctx, punctAssign)) {
        if (!inDecl || tag != symId)
            errorIllegalOutside(ctx, "initializer", "a declaration");

        Node = astCreateBOP(loc, Node, opAssign, parserAssignValue(ctx));
        Node->symbol = Node->l->symbol;
        Node->symbol->impl = Node->r;
    }

    debugLeave();

    return Node;
}
Beispiel #16
0
/**
 * DeclBasic = [ "const" ] <Ident> | StructUnion | Enum
 */
static ast* parserDeclBasic (parserCtx* ctx) {
    debugEnter("DeclBasic");

    ast* Node;

    tokenLocation constloc = ctx->location;
    bool isConst = tokenTryMatchKeyword(ctx, keywordConst);

    if (tokenIsKeyword(ctx, keywordStruct) || tokenIsKeyword(ctx, keywordUnion))
        Node = parserStructOrUnion(ctx);

    else if (tokenIsKeyword(ctx, keywordEnum))
        Node = parserEnum(ctx);

    else {
        tokenLocation loc = ctx->location;
        sym* Symbol = symFind(ctx->scope, ctx->lexer->buffer);

        if (Symbol) {
            Node = astCreateLiteralIdent(loc, tokenDupMatch(ctx));
            Node->symbol = Symbol;

        } else {
            if (tokenIsIdent(ctx)) {
                errorUndefType(ctx);
                tokenNext(ctx);

            } else
                errorExpected(ctx, "type name");

            Node = astCreateInvalid(loc);
        }
    }

    if (isConst) {
        Node = astCreateConst(constloc, Node);
        Node->symbol = Node->r->symbol;
    }

    debugLeave();

    return Node;
}
Beispiel #17
0
/**
 * Storage = [ "auto" | "static" | "extern" | "typedef" ]
 */
static ast* parserStorage (parserCtx* ctx, symTag* tag) {
    debugEnter("Storage");

    ast* Node = 0;

    markerTag marker =   tokenIsKeyword(ctx, keywordAuto) ? markerAuto
                       : tokenIsKeyword(ctx, keywordStatic) ? markerStatic
                       : tokenIsKeyword(ctx, keywordExtern) ? markerExtern : markerUndefined;

    if (tokenTryMatchKeyword(ctx, keywordTypedef))
        *tag = symTypedef;

    else if (marker) {
        Node = astCreateMarker(ctx->location, marker);
        tokenMatch(ctx);
    }

    debugLeave();

    return Node;
}
Beispiel #18
0
/**
 * DeclUnary = ( "*" | "const" DeclUnary ) | DeclObject
 */
static ast* parserDeclUnary (parserCtx* ctx, bool inDecl, symTag tag) {
    debugEnter("DeclUnary");

    ast* Node;
    tokenLocation loc = ctx->location;

    if (tokenTryMatchPunct(ctx, punctTimes)) {
        Node = astCreateUOP(loc, opDeref, parserDeclUnary(ctx, inDecl, tag));
        Node->symbol = Node->r->symbol;

    } else if (tokenTryMatchKeyword(ctx, keywordConst)) {
        Node = astCreateConst(loc, parserDeclUnary(ctx, inDecl, tag));
        Node->symbol = Node->r->symbol;

    } else
        Node = parserDeclObject(ctx, inDecl, tag);

    debugLeave();

    return Node;
}
Beispiel #19
0
/**
 * Name = <UnqualifiedIdent>
 *
 * If inDecl, creates a symbol, adding it to the list of declarations
 * if already created.
 */
static ast* parserName (parserCtx* ctx, bool inDecl, symTag tag) {
    debugEnter("Name");

    ast* Node;

    if (tokenIsIdent(ctx)) {
        tokenLocation loc = ctx->location;
        Node = astCreateLiteralIdent(loc, tokenDupMatch(ctx));

        /*Check for a collision only in this scope, will shadow any
          other declarations elsewhere.*/
        sym* Symbol = symFind(ctx->scope, (char*) Node->literal);

        if (Symbol) {
            Node->symbol = Symbol;
            symChangeParent(Symbol, ctx->scope);

            if (Node->symbol->tag != tag && !isTypedefException(Node->symbol, tag))
                errorRedeclaredSymAs(ctx, Node->symbol, tag);

        } else if (inDecl)
            Node->symbol = symCreateNamed(tag, ctx->scope, (char*) Node->literal);

        if (Node->symbol) {
            /*Can't tell whether this is a duplicate declaration
              or a (matching) redefinition*/
            vectorPush(&Node->symbol->decls, Node);
        }

    } else {
        errorExpected(ctx, "name");
        Node = astCreateInvalid(ctx->location);
        Node->literal = strdup("");
        Node->symbol = symCreateNamed(tag, ctx->scope, "");
    }

    debugLeave();

    return Node;
}
Beispiel #20
0
void analyzerDecl (analyzerCtx* ctx, ast* Node, bool module) {
    debugEnter("Decl");

    /*The storage qualifier given in /this/ declaration, if any*/
    const storageTag storage = analyzerStorage(ctx, Node->r);

    const type* BasicDT = analyzerDeclBasic(ctx, Node->l);

    for (ast* Current = Node->firstChild;
         Current;
         Current = Current->nextSibling) {
        const type* R = analyzerDeclNode(ctx, Current, typeDeepDuplicate(BasicDT), module, storage);

        /*Complete? Avoid complaining about typedefs and the like
          (they don't need to be complete)*/
        if (   Current->symbol && Current->symbol->tag == symId
            && !typeIsComplete(R))
            errorIncompleteDecl(ctx, Current, R);
    }

    debugLeave();
}
Beispiel #21
0
/**
 * Decl = Storage DeclBasic ";" | ( DeclExpr#   ( [{ "," DeclExpr# }] ";" )
 *                                            | FnImpl )
 *
 * DeclExpr is told to require identifiers, allow initiations and
 * create symbols.
 */
ast* parserDecl (parserCtx* ctx, bool module) {
    debugEnter("Decl");

    tokenLocation loc = ctx->location;

    symTag tag = symId;
    ast* storage = parserStorage(ctx, &tag);
    ast* Node = astCreateDecl(loc, parserDeclBasic(ctx));
    Node->r = storage;

    /*Declares no symbols*/
    if (tokenTryMatchPunct(ctx, punctSemicolon))
        ;

    else {
        astAddChild(Node, parserDeclExpr(ctx, true, tag));

        /*Function*/
        if (tokenIsPunct(ctx, punctLBrace)) {
            if (!module)
                errorIllegalOutside(ctx, "function implementation", "module level code");

            Node = parserFnImpl(ctx, Node);

        /*Regular decl*/
        } else {
            while (tokenTryMatchPunct(ctx, punctComma))
                astAddChild(Node, parserDeclExpr(ctx, true, tag));

            tokenMatchPunct(ctx, punctSemicolon);
        }
    }

    debugLeave();

    return Node;
}
Beispiel #22
0
static const type* analyzerDeclBasic (analyzerCtx* ctx, ast* Node) {
    debugEnter(astTagGetStr(Node->tag));

    if (Node->tag == astStruct)
        analyzerStruct(ctx, Node);

    else if (Node->tag == astUnion)
        analyzerUnion(ctx, Node);

    else if (Node->tag == astEnum)
        analyzerEnum(ctx, Node);

    else if (Node->tag == astLiteral) {
        if (Node->litTag == literalIdent)
            Node->dt = typeCreateBasic(Node->symbol);

        else {
            debugErrorUnhandled("analyzerDeclBasic", "literal tag", literalTagGetStr(Node->litTag));
            Node->dt = typeCreateInvalid();
        }

    } else if (Node->tag == astConst) {
        Node->dt = typeDeepDuplicate(analyzerDeclBasic(ctx, Node->r));
        Node->dt->qual.isConst = true;

    } else {
        if (Node->tag != astInvalid)
            debugErrorUnhandled("analyzerDeclBasic", "AST tag", astTagGetStr(Node->tag));

        Node->dt = typeCreateInvalid();
    }

    debugLeave();

    return Node->dt;
}