예제 #1
0
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);
}
예제 #2
0
파일: scope.c 프로젝트: bbu/quaint-lang
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;
}