/** * 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(); }
/** * 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; }
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; }
/** * 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; }
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; }
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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
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(); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
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(); }
/** * 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; }
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; }