/** * 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; }
parserResult parse (sym* global, lexerCtx* lexer) { parserCtx ctx = parserInit(global, lexer); ast* tree = parseS(&ctx); if (!tree) { errprintf("No syntax tree created\n"); tree = astCreateInvalid(); } parserResult result = { .tree = tree, .errors = ctx.errors }; parserFree(&ctx); return result; }
/** * Pattern = <Name> */ static ast* parserPattern (parserCtx* ctx) { ast* node; //todo accept only [\w\d-] if (see_kind(ctx, tokenNormal)) { sym* symbol = symAdd(ctx->scope, ctx->current.buffer); accept(ctx); node = astCreateSymbol(symbol); } else { expected(ctx, "function argument"); node = astCreateInvalid(); } 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; }
/** * FnApp = { Atom | ( "`" Atom "`" ) } * * A series of at least one expr-atom. If multiple, then the last is a * function to which the others are applied. Instead, one of them may * be explicitly marked in backticks as the function. */ static ast* parseFnApp (parserCtx* ctx) { /*Filled iff there is a backtick function*/ ast* fn = 0; vector(ast*) nodes = vectorInit(3, malloc); /*Require at least one expr*/ if (!see(ctx, "!")) vectorPush(&nodes, parseAtom(ctx)); while (waiting_for_delim(ctx)) { if (try_match(ctx, "!")) { if (fn) { error(ctx)("Multiple explicit functions: '%s'\n", ctx->current.buffer); vectorPush(&nodes, fn); } fn = parseAtom(ctx); } else vectorPush(&nodes, parseAtom(ctx)); } if (fn) return astCreateFnApp(nodes, fn); else if (nodes.length == 0) { /*Shouldn't happen due to the way it parses*/ errprintf("FnApp took no AST nodes"); return astCreateInvalid(); } else if (nodes.length == 1) { /*No application*/ ast* node = vectorPop(&nodes); vectorFree(&nodes); return node; } else { /*The last node is the fn*/ fn = vectorPop(&nodes); return astCreateFnApp(nodes, fn); } }
/** * 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; }
/** * Atom = ( "(" [ Expr [{ "," Expr }] ] ")" ) * | ( "[" [{ Expr }] "]" ) * | FnLit | Path | <Str> | <Symbol> */ static ast* parseAtom (parserCtx* ctx) { ast* node; if (try_match(ctx, "(")) { /*Empty brackets => unit literal*/ if (see(ctx, ")")) node = astCreateUnitLit(); else { node = parseExpr(ctx); /*Tuple literal*/ if (see(ctx, ",")) { vector(ast*) nodes = vectorInit(3, malloc); vectorPush(&nodes, node); while (try_match(ctx, ",")) vectorPush(&nodes, parseExpr(ctx)); node = astCreateTupleLit(nodes); } } match(ctx, ")"); /*List literal*/ } else if (try_match(ctx, "[")) { vector(ast*) nodes = vectorInit(4, malloc); if (waiting_for(ctx, "]")) do { vectorPush(&nodes, parseExpr(ctx)); } while (try_match(ctx, ",")); node = astCreateListLit(nodes); match(ctx, "]"); } else if (see(ctx, "\\")) { node = parseFnLit(ctx); } else if (see(ctx, "true") || see(ctx, "false")) { node = astCreateBoolLit(see(ctx, "true")); accept(ctx); } else if (see_kind(ctx, tokenIntLit)) { node = astCreateIntLit(atoi(ctx->current.buffer)); accept(ctx); } else if (see_kind(ctx, tokenStrLit)) { node = astCreateStrLit(ctx->current.buffer); accept(ctx); } else if (see_kind(ctx, tokenNormal)) { sym* symbol; if (isPathToken(ctx->current.buffer)) node = parsePath(ctx); else if ((symbol = symLookup(ctx->scope, ctx->current.buffer))) node = astCreateSymbol(symbol); else node = astCreateFileLit(ctx->current.buffer); accept(ctx); } else { expected(ctx, "expression"); node = astCreateInvalid(); } return node; }