int main(int argc, char *argv[]) { int ch; int retval; char *inputfilename; scope_t *sentinal; STAILQ_INIT(&patches); SLIST_INIT(&search_path); STAILQ_INIT(&seq_program); TAILQ_INIT(&cs_tailq); SLIST_INIT(&scope_stack); /* Set Sentinal scope node */ sentinal = scope_alloc(); sentinal->type = SCOPE_ROOT; includes_search_curdir = 1; appname = *argv; regfile = NULL; listfile = NULL; #if DEBUG yy_flex_debug = 0; mm_flex_debug = 0; yydebug = 0; mmdebug = 0; #endif while ((ch = getopt(argc, argv, "d:i:l:n:o:p:r:I:X")) != -1) { switch(ch) { case 'd': #if DEBUG if (strcmp(optarg, "s") == 0) { yy_flex_debug = 1; mm_flex_debug = 1; } else if (strcmp(optarg, "p") == 0) { yydebug = 1; mmdebug = 1; } else { fprintf(stderr, "%s: -d Requires either an " "'s' or 'p' argument\n", appname); usage(); } #else stop("-d: Assembler not built with debugging " "information", EX_SOFTWARE); #endif break; case 'i': stock_include_file = optarg; break; case 'l': /* Create a program listing */ if ((listfile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } listfilename = optarg; break; case 'n': /* Don't complain about the -nostdinc directrive */ if (strcmp(optarg, "ostdinc")) { fprintf(stderr, "%s: Unknown option -%c%s\n", appname, ch, optarg); usage(); /* NOTREACHED */ } break; case 'o': if ((ofile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } ofilename = optarg; break; case 'p': /* Create Register Diagnostic "printing" Functions */ if ((regdiagfile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } regdiagfilename = optarg; break; case 'r': if ((regfile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } regfilename = optarg; break; case 'I': { path_entry_t include_dir; if (strcmp(optarg, "-") == 0) { if (includes_search_curdir == 0) { fprintf(stderr, "%s: Warning - '-I-' " "specified multiple " "times\n", appname); } includes_search_curdir = 0; for (include_dir = SLIST_FIRST(&search_path); include_dir != NULL; include_dir = SLIST_NEXT(include_dir, links)) /* * All entries before a '-I-' only * apply to includes specified with * quotes instead of "<>". */ include_dir->quoted_includes_only = 1; } else { include_dir = (path_entry_t)malloc(sizeof(*include_dir)); if (include_dir == NULL) { perror(optarg); stop(NULL, EX_OSERR); } include_dir->directory = strdup(optarg); if (include_dir->directory == NULL) { perror(optarg); stop(NULL, EX_OSERR); } include_dir->quoted_includes_only = 0; SLIST_INSERT_HEAD(&search_path, include_dir, links); } break; } case 'X': /* icc version of -nostdinc */ break; case '?': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) { fprintf(stderr, "%s: No input file specifiled\n", appname); usage(); /* NOTREACHED */ } if (regdiagfile != NULL && (regfile == NULL || stock_include_file == NULL)) { fprintf(stderr, "%s: The -p option requires the -r and -i options.\n", appname); usage(); /* NOTREACHED */ } symtable_open(); inputfilename = *argv; include_file(*argv, SOURCE_FILE); retval = yyparse(); if (retval == 0) { if (SLIST_FIRST(&scope_stack) == NULL || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { stop("Unterminated conditional expression", EX_DATAERR); /* NOTREACHED */ } /* Process outmost scope */ process_scope(SLIST_FIRST(&scope_stack)); /* * Decend the tree of scopes and insert/emit * patches as appropriate. We perform a depth first * tranversal, recursively handling each scope. */ /* start at the root scope */ dump_scope(SLIST_FIRST(&scope_stack)); /* Patch up forward jump addresses */ back_patch(); if (ofile != NULL) output_code(); if (regfile != NULL) symtable_dump(regfile, regdiagfile); if (listfile != NULL) output_listing(inputfilename); } stop(NULL, 0); /* NOTREACHED */ return (0); }
static inline size_t add_builtins(const struct ast_unit *const unit) { size_t offset = 0; for (scope_bcon_id_t id = 0; id < SCOPE_BCON_ID_COUNT; ++id) { unit->scope->objs[offset++] = (struct scope_obj) { .name = scope_builtin_consts[id].name, .obj = SCOPE_OBJ_BCON, .bcon_id = id, }; } for (scope_bfun_id_t id = 0; id < SCOPE_BFUN_ID_COUNT; ++id) { unit->scope->objs[offset++] = (struct scope_obj) { .name = scope_builtin_funcs[id].name, .obj = SCOPE_OBJ_BFUN, .bfun_id = id, }; } return offset; } static int scope_build_inner(struct ast_node *const node, const struct scope *const outer) { assert(node != NULL); static struct ast_func *outer_func; int error = SCOPE_OK; switch (node->an) { case AST_AN_FUNC: { struct ast_func *const func = ast_data(node, func); const size_t objcount = count_objects_block(node); assert(func->scope == NULL); if (unlikely(!(func->scope = scope_alloc(objcount)))) { return NOMEM; } func->scope->outer = outer; func->scope->objcount = objcount; size_t offset = 0; for (size_t param_idx = 0; param_idx < func->param_count; ++param_idx) { func->scope->objs[offset++] = (struct scope_obj) { .name = func->params[param_idx].name, .obj = SCOPE_OBJ_PARM, .type = func->params[param_idx].type, }; } outer_func = func; for (size_t idx = 0; idx < func->stmt_count; ++idx) { struct ast_node *const stmt = func->stmts[idx]; if (unlikely(!stmt)) { continue; } if (stmt->an == AST_AN_DECL) { const struct ast_decl *const decl = ast_data(stmt, decl); for (size_t name_idx = 0; name_idx < decl->name_count; ++name_idx) { func->scope->objs[offset++] = (struct scope_obj) { .name = decl->names[name_idx], .obj = SCOPE_OBJ_AVAR, .decl = stmt, }; } } else if (stmt->an == AST_AN_WLAB) { aggr_error(&error, add_func_wlab(func, stmt)); } else { aggr_error(&error, scope_build_inner(stmt, func->scope)); } } qsort(func->wlabs, func->wlab_count, sizeof(*func->wlabs), cmp_scope_obj); identify_wlabs(func); aggr_error(&error, find_duplicates(func->scope->objs, objcount)); qsort(func->scope->objs, objcount, sizeof(struct scope_obj), cmp_scope_obj); } break; case AST_AN_BLOK: case AST_AN_NOIN: case AST_AN_WHIL: case AST_AN_DOWH: { struct scope **scope; size_t stmt_count; struct ast_node **stmts; const size_t objcount = count_objects_block(node); if (node->an == AST_AN_BLOK || node->an == AST_AN_NOIN) { struct ast_blok *const blok = ast_data(node, blok); scope = &blok->scope; stmt_count = blok->stmt_count; stmts = blok->stmts; } else { struct ast_whil *const whil = ast_data(node, whil); scope = &whil->scope; stmt_count = whil->stmt_count; stmts = whil->stmts; } assert(*scope == NULL); if (unlikely(!(*scope = scope_alloc(objcount)))) { return NOMEM; } (*scope)->outer = outer; (*scope)->objcount = objcount; for (size_t idx = 0, offset = 0; idx < stmt_count; ++idx) { struct ast_node *const stmt = stmts[idx]; if (unlikely(!stmt)) { continue; } if (stmt->an == AST_AN_DECL) { const struct ast_decl *const decl = ast_data(stmt, decl); for (size_t name_idx = 0; name_idx < decl->name_count; ++name_idx) { (*scope)->objs[offset++] = (struct scope_obj) { .name = decl->names[name_idx], .obj = SCOPE_OBJ_AVAR, .decl = stmt, }; } } else if (stmt->an == AST_AN_WLAB) { aggr_error(&error, add_func_wlab(outer_func, stmt)); } else { aggr_error(&error, scope_build_inner(stmt, *scope)); } } aggr_error(&error, find_duplicates((*scope)->objs, objcount)); qsort((*scope)->objs, objcount, sizeof(struct scope_obj), cmp_scope_obj); } break; case AST_AN_COND: { struct ast_cond *const cond = ast_data(node, cond); aggr_error(&error, scope_build_inner(cond->if_block, outer)); for (size_t idx = 0; idx < cond->elif_count; ++idx) { aggr_error(&error, scope_build_inner(cond->elif[idx].block, outer)); } if (cond->else_block) { aggr_error(&error, scope_build_inner(cond->else_block, outer)); } } break; } return error; } int scope_build(struct ast_node *const root) { assert(root != NULL); struct ast_unit *const unit = ast_data(root, unit); size_t objcount = count_objects_unit(unit); assert(unit->scope == NULL); if (unlikely(!(unit->scope = scope_alloc(objcount)))) { return NOMEM; } unit->scope->objcount = objcount; size_t offset = add_builtins(unit); int error = SCOPE_OK; for (size_t idx = 0; idx < unit->stmt_count; ++idx) { struct ast_node *const stmt = unit->stmts[idx]; if (unlikely(!stmt)) { continue; } if (stmt->an == AST_AN_DECL) { const struct ast_decl *const decl = ast_data(stmt, decl); for (size_t name_idx = 0; name_idx < decl->name_count; ++name_idx) { unit->scope->objs[offset++] = (struct scope_obj) { .name = decl->names[name_idx], .obj = SCOPE_OBJ_GVAR, .decl = stmt, }; } } else if (stmt->an == AST_AN_FUNC) { const struct ast_func *const func = ast_data(stmt, func); unit->scope->objs[offset++] = (struct scope_obj) { .name = func->name, .obj = SCOPE_OBJ_FUNC, .func = stmt, }; aggr_error(&error, scope_build_inner(stmt, unit->scope)); } } aggr_error(&error, find_duplicates(unit->scope->objs, objcount)); qsort(unit->scope->objs, objcount, sizeof(struct scope_obj), cmp_scope_obj); return error; } struct scope_obj *scope_find_object(const struct scope *scope, const struct lex_symbol *const name) { const struct scope_obj needle = { .name = name }; do { struct scope_obj *const found = bsearch(&needle, scope->objs, scope->objcount, sizeof(struct scope_obj), cmp_scope_obj); if (found && found->obj != SCOPE_OBJ_DUPL) { if (found->obj == SCOPE_OBJ_AVAR) { const struct ast_decl *const decl = ast_data(found->decl, decl); return likely(name->beg > decl->names[0]->beg) ? found : NULL; } else { return found; } } } while ((scope = scope->outer)); return NULL; } ptrdiff_t scope_find_wlab(const struct ast_func *const func, const struct lex_symbol *const name) { const struct scope_obj needle = { .name = name }; const ssize_t elem_size = sizeof(*func->wlabs); const void *const found = bsearch(&needle, func->wlabs, func->wlab_count, (size_t) elem_size, cmp_scope_obj); return likely(found) ? ((char *) found - (char *) func->wlabs) / elem_size : -1; }