ref: dcb761aebd2815fdf2d04c0b05724292de9dc98b
dir: /parse.c/
#include <u.h> #include <libc.h> #include <thread.h> #include "dat.h" #include "fns.h" static void _Noreturn error(TokenList *, char *); static int peek(TokenList *); static int peekclass(TokenList *); static void match(TokenList *, int); static void addchild(Ast *, Ast *); static int issep(TokenList *t); static int nameclass(char *, Ast *); static void parsesep(TokenList *); static void parseseps(TokenList *, int); static Ast *parseprog(TokenList *); static Ast *parsefuncdef(TokenList *); static Ast *parsefuncheader(TokenList *); static Ast *parselocals(TokenList *); static Ast *parseexpr(TokenList *, Ast *); static Ast *parseexprsub(TokenList *); static Ast *parseline(TokenList *); static Ast *parsename(TokenList *); static Ast *parsefunc(TokenList *); static Ast *parseconst(TokenList *); Ast * parse(TokenList *tokens, char **errp) { Ast *ast; tokens->offset = 0; tokens->err = nil; if(setjmp(tokens->errbuf)){ *errp = tokens->err; return nil; }else{ ast = parseprog(tokens); match(tokens, TokEnd); } return ast; } static void _Noreturn error(TokenList *tokens, char *msg) { tokens->err = msg; longjmp(tokens->errbuf, 1); } static int peek(TokenList *tokens) { if(tokens->offset >= tokens->count) error(tokens, "unexpected end of token stream"); return tokens->tokens[tokens->offset].tag; } static int peekclass(TokenList *tokens) { peek(tokens); /* triggers an error if we are at the end */ return tokens->tokens[tokens->offset].nameclass; } static void match(TokenList *tokens, int tag) { if(peek(tokens) != tag) error(tokens, "Unexpected token (match failed)"); tokens->offset++; } static void addchild(Ast *ast, Ast *child) { ast->childcount++; ast->children = allocextra(ast, sizeof(Ast *) * ast->childcount); ast->children[ast->childcount-1] = child; } static int issep(TokenList *t) { switch(peek(t)){ case TokNewline: case TokDiamond: return 1; default: return 0; } } static int nameclass(char *name, Ast *func) { int class; if(func == nil) class = NameclassUndef; else if(strcmp(name, func->funcname->name) == 0) class = NameclassFunc; else if(func->funcresult && strcmp(name, func->funcresult->name) == 0) class = NameclassLocal; else if(func->funcleftarg && strcmp(name, func->funcleftarg->name) == 0) class = NameclassLocal; else if(func->funcrightarg && strcmp(name, func->funcrightarg->name) == 0) class = NameclassLocal; else{ /* Check if the name exist in the locallist */ class = NameclassUndef; } return class; } static void parsesep(TokenList *t) { if(issep(t)) match(t, peek(t)); } static void parseseps(TokenList *t, int required) { while(issep(t)){ match(t, peek(t)); required = 0; } if(required) match(t, TokNewline); } static Ast * parseprog(TokenList *t) { Ast *prog = alloc(DataAst); prog->tag = AstProg; while(peek(t) != TokEnd){ Ast *child; if(peek(t) == TokDel) child = parsefuncdef(t); else child = parseexpr(t, nil); print("After expr: %d\n", peek(t)); if(peek(t) != TokEnd) parseseps(t, 1); addchild(prog, child); } print("got prog, peek is: %d\n", peek(t)); return prog; } static Ast * parsefuncdef(TokenList *t) { Ast *func = parsefuncheader(t); while(peek(t) != TokDel){ Ast *expr = parseexpr(t, func); addchild(func, expr); if(peek(t) != TokDel) parseseps(t, 1); } match(t, TokDel); return func; } static Ast * parsefuncheader(TokenList *t) { Ast *func = alloc(DataAst); func->tag = AstFunc; match(t, TokDel); func->funcname = parsename(t); if(peek(t) == TokLarrow){ match(t, TokLarrow); func->funcresult = func->funcname; func->funcname = parsename(t); } if(peek(t) == TokName) func->funcrightarg = parsename(t); if(peek(t) == TokName){ func->funcleftarg = func->funcname; func->funcname = func->funcrightarg; func->funcrightarg = parsename(t); } func->funclocals = parselocals(t); return func; } static Ast * parselocals(TokenList *t) { Ast *locals = alloc(DataAst); locals->tag = AstLocals; while(peek(t) == TokSemi){ match(t, TokSemi); Ast *name = parsename(t); name->nameclass = NameclassLocal; addchild(locals, name); } parseseps(t, 1); return locals; } static Ast * parseexpr(TokenList *t, Ast *func) { uvlong start, end; vlong depth; depth = 0; start = t->offset; while(!(issep(t) || (peek(t) == TokDel) || (peek(t) == TokEnd)) || depth != 0){ switch(peek(t)){ case TokLparen: depth++; break; case TokRparen: depth--; break; } match(t, peek(t)); } end = t->offset; t->offset = start; for(uvlong i = start; i < end; i++){ char *name; int class; if(t->tokens[i].tag != TokName) continue; name = t->tokens[i].name; class = nameclass(name, func); t->tokens[i].nameclass = class; if(class == 0) error(t, "parseexpr() can't deal with free variables yet"); } /* We know the nameclass of each name, and assume that the nameclasses do not change. * Now create the AST. */ return parseexprsub(t); } static Ast * parseexprsub(TokenList *t) { Ast *expr, *val; if(peek(t) == TokLparen){ match(t, TokLparen); val = parseexprsub(t); match(t, TokRparen); }else val = nil; if(peekclass(t) == NameclassFunc){ func: expr = alloc(DataAst); if(val){ expr->tag = AstDyadic; expr->left = val; }else expr->tag = AstMonadic; expr->func = parsefunc(t); expr->right = parseexprsub(t); return expr; } if(peek(t) == TokName){ val = parsename(t); if(peek(t) == TokLarrow){ match(t, TokLarrow); expr = alloc(DataAst); expr->tag = AstAssign; expr->left = val; expr->right = parseexprsub(t); return expr; } } /* We need a value now. Stranding is not implemented */ if(val == nil) val = parseconst(t); if(peekclass(t) == NameclassFunc) goto func; return val; } static Ast * parsename(TokenList *t) { Ast *name = alloc(DataAst); name->tag = AstName; name->name = t->tokens[t->offset].name; match(t, TokName); return name; } static Ast * parsefunc(TokenList *t) { /* TODO: parse primitives as well */ Ast *func; if(peek(t) == TokName && peekclass(t) == NameclassFunc) func = parsename(t); else{ func = alloc(DataAst); func->tag = AstPrim; func->prim = t->tokens[t->offset].prim; match(t, TokPrimitive); } return func; } static Ast * parseconst(TokenList *t) { Ast *val = alloc(DataAst); val->tag = AstConst; vlong num = t->tokens[t->offset].num; match(t, TokNumber); val->val = allocarray(TypeNumber, 0, 1); setint(val->val, 0, num); return val; }