#include #include #include #include #include #include "ply.h" struct providers { provider_t **prov; size_t len; } providers; provider_t *provider_get(const char *name) { size_t i; for (i = 0; i < providers.len; i++) { if (strstr(providers.prov[i]->name, name) == providers.prov[i]->name) return providers.prov[i]; } return NULL; } void provider_register(provider_t *prov) { assert(prov); assert(prov->probe); assert(prov->resolve); providers.prov = realloc(providers.prov, ++providers.len * sizeof(*providers.prov)); providers.prov[providers.len - 1] = prov; } typedef struct pass pass_t; struct pass { int (*run)(pass_t *, prog_t *); walk_fn pre; walk_fn post; }; symtab_t globals = { .sym = NULL, .len = 0 }; symtab_t locals = { .sym = NULL, .len = 0 }; prog_t *prog_get(void) { prog_t *prog; prog = calloc(1, sizeof(*prog)); prog->locals = &locals; prog->globals = &globals; /* (@ ([ reads ((pid))) (quantize arg2)) */ prog->probe = "k:SyS_read"; /* { @reads[pid()] = quantize(arg2) } */ prog->ast = node_list( node_vlist(node_keyword('='), node_vlist(node_keyword('['), node_ident("@reads"), node_list(node_ident("pid")), NULL), node_vlist(node_ident("quantize"), node_ident("arg2"), NULL), NULL) ); prog->provider = provider_get("k"); prog->provider->probe(prog); return prog; } int pass_resolve_symbols(node_t *n, void *_prog) { prog_t *prog = _prog; provider_t *global = provider_get(":"); node_t *op; int err; if (n->ntype != N_IDENT) return 0; /* .IDENT/->IDENT is a struct/union member, skip */ /* op = node_prev(node_prev(n)); */ /* if (op && (op->ntype == N_IDENT) && !strcmp(".", op->ident)) */ /* return 0; */ err = prog->provider->resolve(prog, n); if (!err || (err != -ENOENT)) return err; err = global->resolve(prog, n); if (!err || (err != -ENOENT)) return err; /* neither provider identifier nor global ditto => user * variable, add it as a global symbol of unknown type. */ return sym_add(prog->globals, n->ident, NULL, &n->sym); } int infer_type_list(prog_t *prog, node_t *n) { type_t *t; /* list of lists (code block) => void */ if (n->list->ntype == N_LIST) { n->type = &t_v; return 0; } t = n->list->type; if (!t) return 0; switch (t->ttype) { case T_FUNC: n->type = t->t.func.type; break; default: n->type = t; } return 0; } int infer_type_keyword(prog_t *prog, node_t *n) { node_t *dst, *src; switch (n->keyword) { case KW_ASSIGN: dst = node_next(n); src = node_next(dst); assert(dst && src); if (!src->type) return 0; if (!dst->type) dst->type = src->type; /* TODO: assignment is statement for now. do we need * c-style assignment expressions? e.g `a = b = 2;` */ n->type = &t_v; return 0; default: return 0; } return -ENOSYS; } int infer_type_sym(prog_t *prog, node_t *n) { node_t *parent, *key; if (n->sym->type) return 0; parent = node_up(n); key = node_next(n); /* match `somemap[somekey]` where the type of the entire * expression and the type of the key is known, since that * means the type of the map itself is also known. */ if (parent && parent->type && (parent->list->ntype == N_KEYWORD) && (parent->list->keyword == KW_SUBSCRIPT) && key && key->type) { n->type = type_get_map_of(key->type, parent->type); return sym_add(n->sym->st, n->ident, n->type, NULL); } return 0; } int pass_infer_types(node_t *n, void *_prog) { prog_t *prog = _prog; if (n->type) return 0; switch (n->ntype) { case N_LIST: return infer_type_list(prog, n); case N_KEYWORD: return infer_type_keyword(prog, n); case N_IDENT: return infer_type_sym(prog, n); default: break; } return 0; } int pass_walk(pass_t *pass, prog_t *prog) { return node_walk(prog->ast, pass->pre, pass->post, prog); } pass_t passes[] = { { .run = pass_walk, .post = pass_resolve_symbols }, { .run = pass_walk, .post = pass_infer_types }, { .run = pass_walk, .post = pass_infer_types }, { NULL } }; int main(void) { prog_t *prog = prog_get(); pass_t *pass; int err; for (pass = passes; pass->run; pass++) { err = pass->run(pass, prog); if (err) break; } printf("AST\n===\n"); node_dump(prog->ast, stdout); printf("\nLOCALS\n======\n"); symtab_dump(prog->locals, stdout); printf("\nGLOBALS\n=======\n"); symtab_dump(prog->globals, stdout); /* printf("\nTYPES\n=====\n"); */ /* types_dump_cdecl(stdout); */ return err; }