harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

main.c (4807B)


      1 #include <assert.h>
      2 #include <errno.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <sys/stat.h>
      7 #include <unistd.h>
      8 #include "ast.h"
      9 #include "check.h"
     10 #include "emit.h"
     11 #include "gen.h"
     12 #include "lex.h"
     13 #include "parse.h"
     14 #include "qbe.h"
     15 #include "type_store.h"
     16 #include "typedef.h"
     17 #include "util.h"
     18 
     19 static void
     20 usage(const char *argv_0)
     21 {
     22 	fprintf(stderr,
     23 		"Usage: %s [-a arch] [-D ident[:type]=value] [-o output] [-T] [-t typedefs] [-N namespace] input.ha...\n",
     24 		argv_0);
     25 }
     26 
     27 enum stage {
     28 	STAGE_LEX,
     29 	STAGE_PARSE,
     30 	STAGE_CHECK,
     31 	STAGE_GEN,
     32 	STAGE_EMIT,
     33 };
     34 
     35 static enum stage
     36 parse_stage(const char *s)
     37 {
     38 	if (s == NULL) {
     39 		return STAGE_EMIT;
     40 	} else if (strcmp(s, "lex") == 0) {
     41 		return STAGE_LEX;
     42 	} else if (strcmp(s, "parse") == 0) {
     43 		return STAGE_PARSE;
     44 	} else if (strcmp(s, "check") == 0) {
     45 		return STAGE_CHECK;
     46 	} else if (strcmp(s, "gen") == 0) {
     47 		return STAGE_GEN;
     48 	} else if (strcmp(s, "emit") == 0) {
     49 		return STAGE_EMIT;
     50 	} else {
     51 		fprintf(stderr, "Unknown HA_STAGE value '%s'\n", s);
     52 		exit(EXIT_FAILURE);
     53 	}
     54 }
     55 
     56 static struct ast_global_decl *
     57 parse_define(const char *argv_0, const char *in)
     58 {
     59 	struct ast_global_decl *def = xcalloc(1, sizeof(struct ast_global_decl));
     60 
     61 	struct token tok;
     62 	struct lexer lexer;
     63 	FILE *f = fmemopen((char *)in, strlen(in), "r");
     64 	const char *d = "-D";
     65 	sources = &d;
     66 	lex_init(&lexer, f, 0);
     67 
     68 	parse_identifier(&lexer, &def->ident, false);
     69 	def->type = NULL;
     70 	if (lex(&lexer, &tok) == T_COLON) {
     71 		def->type = parse_type(&lexer);
     72 		lex(&lexer, &tok);
     73 	}
     74 
     75 	if (tok.token != T_EQUAL) {
     76 		lex_finish(&lexer);
     77 		usage(argv_0);
     78 		exit(EXIT_FAILURE);
     79 	}
     80 	def->init = parse_expression(&lexer);
     81 
     82 	lex_finish(&lexer);
     83 	return def;
     84 }
     85 
     86 int
     87 main(int argc, char *argv[])
     88 {
     89 	char *output = NULL, *typedefs = NULL;
     90 	char *target = DEFAULT_TARGET;
     91 	bool is_test = false;
     92 	struct unit unit = {0};
     93 	struct lexer lexer;
     94 	struct ast_global_decl *defines = NULL, **next_def = &defines;
     95 
     96 	int c;
     97 	while ((c = getopt(argc, argv, "D:ho:Tt:N:")) != -1) {
     98 		switch (c) {
     99 		case 'a':
    100 			target = optarg;
    101 			break;
    102 		case 'D':
    103 			*next_def = parse_define(argv[0], optarg);
    104 			next_def = &(*next_def)->next;
    105 			break;
    106 		case 'o':
    107 			output = optarg;
    108 			break;
    109 		case 'T':
    110 			is_test = true;
    111 			break;
    112 		case 't':
    113 			typedefs = optarg;
    114 			break;
    115 		case 'N':
    116 			unit.ns = xcalloc(1, sizeof(struct identifier));
    117 			FILE *in = fmemopen(optarg, strlen(optarg), "r");
    118 			const char *ns = "-N";
    119 			sources = &ns;
    120 			lex_init(&lexer, in, 0);
    121 			parse_identifier(&lexer, unit.ns, false);
    122 			lex_finish(&lexer);
    123 			break;
    124 		case 'h':
    125 		default:
    126 			usage(argv[0]);
    127 			return EXIT_FAILURE;
    128 		}
    129 	}
    130 
    131 	builtin_types_init(target);
    132 
    133 	size_t ninputs = argc - optind;
    134 	if (ninputs == 0) {
    135 		usage(argv[0]);
    136 		return EXIT_FAILURE;
    137 	}
    138 
    139 	struct ast_unit aunit = {0};
    140 	struct ast_subunit *subunit = &aunit.subunits;
    141 	struct ast_subunit **next = &aunit.subunits.next;
    142 	enum stage stage = parse_stage(getenv("HA_STAGE"));
    143 
    144 	sources = xcalloc(ninputs + 2, sizeof(char **));
    145 	memcpy((char **)sources + 1, argv + optind, sizeof(char **) * ninputs);
    146 	sources[0] = "<unknown>";
    147 	sources[ninputs + 1] = NULL;
    148 
    149 	for (size_t i = 0; i < ninputs; ++i) {
    150 		FILE *in;
    151 		const char *path = argv[optind + i];
    152 		if (strcmp(path, "-") == 0) {
    153 			in = stdin;
    154 		} else {
    155 			in = fopen(path, "r");
    156 			struct stat buf;
    157 			if (in && fstat(fileno(in), &buf) == 0
    158 				&& S_ISDIR(buf.st_mode) != 0) {
    159 				fprintf(stderr, "Unable to open %s for reading: Is a directory\n",
    160 					path);
    161 				return EXIT_FAILURE;
    162 			}
    163 		}
    164 
    165 		if (!in) {
    166 			fprintf(stderr, "Unable to open %s for reading: %s\n",
    167 					path, strerror(errno));
    168 			return EXIT_FAILURE;
    169 		}
    170 
    171 		lex_init(&lexer, in,  i + 1);
    172 		if (stage == STAGE_LEX) {
    173 			struct token tok;
    174 			while (lex(&lexer, &tok) != T_EOF);
    175 		} else {
    176 			parse(&lexer, subunit);
    177 			if (i + 1 < ninputs) {
    178 				*next = xcalloc(1, sizeof(struct ast_subunit));
    179 				subunit = *next;
    180 				next = &subunit->next;
    181 			}
    182 		}
    183 		lex_finish(&lexer);
    184 	}
    185 
    186 	if (stage == STAGE_PARSE || stage == STAGE_LEX) {
    187 		return EXIT_SUCCESS;
    188 	}
    189 
    190 	static struct type_store ts = {0};
    191 	check(&ts, is_test, defines, &aunit, &unit);
    192 	if (stage == STAGE_CHECK) {
    193 		return EXIT_SUCCESS;
    194 	}
    195 
    196 	if (typedefs) {
    197 		FILE *out = fopen(typedefs, "w");
    198 		if (!out) {
    199 			fprintf(stderr, "Unable to open %s for writing: %s\n",
    200 					typedefs, strerror(errno));
    201 			return EXIT_FAILURE;
    202 		}
    203 		emit_typedefs(&unit, out);
    204 		fclose(out);
    205 	}
    206 
    207 	struct qbe_program prog = {0};
    208 	gen(&unit, &ts, &prog);
    209 	if (stage == STAGE_GEN) {
    210 		return EXIT_SUCCESS;
    211 	}
    212 
    213 	FILE *out;
    214 	if (!output) {
    215 		out = stdout;
    216 	} else {
    217 		out = fopen(output, "w");
    218 		if (!out) {
    219 			fprintf(stderr, "Unable to open %s for writing: %s\n",
    220 					output, strerror(errno));
    221 			return EXIT_FAILURE;
    222 		}
    223 	}
    224 	emit(&prog, out);
    225 	fclose(out);
    226 	return EXIT_SUCCESS;
    227 }