Ejemplo n.º 1
0
int main(int argc, char *argv[]) {

	// First, we process the user's command-line arguments, which dictate the input file
	// and target processor.

	char* fname, *inname, *outname;
	int c;

	opterr = 0;
	while ((c = getopt (argc, argv, "iaucpsovrm:d:t:")) != -1)
	switch (c)	{
		case 'i':	opt_includeonce = false;	break;
		case 'u':	opt_upload = true;			
		case 'a':	opt_assemble = true;		break;
		case 'c':	opt_cleanup = true;			break;
		case 'p':	opt_primitives = false;		break;
		case 's':	opt_stdlib = false;			break;
		case 'o':	opt_aggressive = false;		break;
		case 'v':	opt_verbose = true;			break;
		case 'r':	opt_verify = true;			break;
		case 'm':	model = optarg;				break;
		case 'd':	device = optarg;			break;
		case 't':	treeshaker_max_rounds = atoi(optarg);	break;
		case '?':
			if (optopt == 'm')
				fprintf (stderr, "Option -%c requires an argument.\n", optopt);
			else if (isprint (optopt))
				fprintf (stderr, "Unknown option `-%c'.\n", optopt);
			else
				fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
			return 1;
		default:
			abort ();
	}

	fprintf(stdout, "Microscheme 0.8, (C) Ryan Suchocki\n");

	if (argc < 2) {
		fprintf(stdout, "usage: microscheme [-iaucpsov] [-m model] [-d device] [-t treeshaker-rounds] program[.ms]\n");
		return(EXIT_FAILURE);
	}

	fname=argv[optind];

	if (strncmp(fname + strlen(fname) - 3, ".ms", 3) == 0)
		fname[strlen(fname) - 3] = 0;

	inname=str_clone_more(fname, 3);
	outname=str_clone_more(fname, 2);
	strcat(inname, ".ms");
	strcat(outname, ".s");

	if (argc == optind) {
		fprintf(stderr, "No input file.\n");
		exit(EXIT_FAILURE);
	}

	if (argc > optind + 1) {
		fprintf(stderr, "Multiple input files not yet supported.\n");
		exit(EXIT_FAILURE);
	}








	// This function controls the overall compilation process, which is implemented
	// as four seperate phases, invoked in order.

	// 1) Lex the file
	lexer_tokenNode *root = NULL;

	if (opt_primitives)
		root = lexer_lexBlob(src_primitives_ms, src_primitives_ms_len, root);

	if (opt_stdlib)
		root = lexer_lexBlob(src_stdlib_ms, src_stdlib_ms_len, root);

	root = lexer_lexFile(inname, root);

	globalIncludeList = try_malloc(sizeof(char*));
	globalIncludeList[0] = str_clone(inname);
	globalIncludeListN = 1;

	// 2) Parse the file
	AST_expr *ASTroot = parser_parseFile(root->children, root->numChildren, true);

	// (We can free the memory used by the lexer once the parser has finished)...
	lexer_freeTokenTree(root);

	// We set up a global environment:
	globalEnv = try_malloc(sizeof(Environment));
	scoper_initEnv(globalEnv);

	// And hand it to the scoper...
	currentEnvironment = globalEnv;

	// At the top level, there is no 'current closure', and hence no 'current closure environment'
	currentClosureEnvironment = NULL;

	// 3) Scope the file:
	ASTroot = scoper_scopeExpr(ASTroot);

	numPurgedGlobals = -1;
	int latestpurge = -2;
	int rounds = 0;

	if (opt_aggressive) {
		globalEnv->realAddress = try_malloc(sizeof(int) * globalEnv->numBinds);
		int i;
		for (i = 0; i < globalEnv->numBinds; i++) {
			globalEnv->realAddress[i] = 0;
		}

		while ((numPurgedGlobals > latestpurge) && (rounds < treeshaker_max_rounds)) {
			//fprintf(stderr, ">> ROUND %i\n", roundi);
			rounds++;
			latestpurge = numPurgedGlobals;

			treeshaker_shakeExpr(ASTroot);
			treeshaker_purge();

			//fprintf(stderr, ">> Aggressive: %i globals purged!\n", numPurgedGlobals);
		} 

		fprintf(stdout, ">> Treeshaker: After %i rounds: %i globals purged! %i bytes will be reserved.\n", rounds, numPurgedGlobals, numUsedGlobals * 2);

		if (opt_verbose) {
			fprintf(stdout, ">> Remaining globals: [");
			int i;
			for (i = 0; i < globalEnv->numBinds; i++) {
				if (globalEnv->realAddress[i] >= 0)
					fprintf(stdout, "%s ", globalEnv->binding[i]);
			}
			fprintf(stdout, "]\n");
		}

		
	} else {
		numUsedGlobals = globalEnv->numBinds;
	}

	// 4) Generate code. (Starting with some preamble)

	FILE *outputFile;
	outputFile = fopen(outname, "w");

		codegen_emitModelHeader(model, outputFile);
		codegen_emitPreamble(outputFile, numUsedGlobals);

		// Next, we recursively emit code for the actual program body:
		codegen_emit(ASTroot, 0, outputFile, model, NULL, opt_aggressive, globalEnv);

		// Finally, we emit some postamble code
		codegen_emitPostamble(outputFile);

	fclose(outputFile);

	// Finally, the memory allocated during parsing can be freed.
	parser_freeAST(ASTroot);
	freeEnvironment(globalEnv);

	// If we've reached this stage, then everything has gone OK:
	fprintf(stdout, ">> %i lines compiled OK\n", fileLine);






	char cmd[100];
	char *STR_LEVEL, *STR_TARGET, *STR_PROG, *STR_BAUD;

	if (strcmp(model, "MEGA") == 0) {
		STR_LEVEL  = "avr6";
		STR_TARGET = "atmega2560";
		STR_PROG   = "wiring";
		STR_BAUD   = "115200";
	} else if (strcmp(model, "UNO") == 0) {
		STR_LEVEL  = "avr5";
		STR_TARGET = "atmega328p";
		STR_PROG   = "arduino";
		STR_BAUD   = "115200";
	} else if (strcmp(model, "LEO") == 0) {
		STR_LEVEL  = "avr5";
		STR_TARGET = "atmega32u4";
		STR_PROG   = "arduino";
		STR_BAUD   = "115200";
	} else {
		fprintf(stderr, "Device not supported.\n");
		return EXIT_FAILURE;
	}




	if (opt_assemble) {
		if (strcmp(model, "") == 0) {
			fprintf(stderr, "Model Not Set. Cannot assemble.\n");
			return EXIT_FAILURE;
		}

		fprintf(stderr, ">> Assembling...\n");
		sprintf(cmd, "avr-gcc -mmcu=%s -o %s.elf %s.s", STR_LEVEL, fname, fname);

		try_execute(cmd);

		sprintf(cmd, "avr-objcopy --output-target=ihex %s.elf %s.hex", fname, fname);
		
		try_execute(cmd);
	}

	if (opt_upload) {

		if (strcmp(device, "") == 0) {
			fprintf(stderr, "Device Not Set. Cannot upload.\n");
			return EXIT_FAILURE;
		}

		fprintf(stderr, ">> Uploading...\n");

		char *opt1, *opt2;
		if (opt_verbose) opt1 = "-v"; else opt1 = "";
		if (opt_verify) opt2 = ""; else opt2 = "-V";

		sprintf(cmd, "avrdude %s %s -p %s -c %s -P %s -b %s -D -U flash:w:%s.hex:i", opt1, opt2, STR_TARGET, STR_PROG, device, STR_BAUD, fname);
		
		try_execute(cmd);
	}

	if (opt_cleanup) {
		fprintf(stdout, ">> Cleaning Up...\n");

		#ifdef __WIN32 // Defined for both 32 and 64 bit environments
			sprintf(cmd, "del %s.s %s.elf %s.hex", fname, fname, fname);
		#else
			sprintf(cmd, "rm -f %s.s %s.elf %s.hex", fname, fname, fname);
		#endif

		try_execute(cmd);
	}

	fprintf(stdout, ">> Finished.\n");

	try_free(inname);
	try_free(outname);

	int i;
	for (i=0; i<globalIncludeListN; i++)
		try_free(globalIncludeList[i]);

	try_free(globalIncludeList);

	return EXIT_SUCCESS;
}
Ejemplo n.º 2
0
int main(int argc, char *argv[]) {

	// First, we process the user's command-line arguments, which dictate the input file
	// and target processor.

	char *inname, *outname, *basename, *shortbase;
	int c;

	fprintf(stdout, "Microscheme 0.9.3, (C) Ryan Suchocki\n");

	char *helpmsg = "\nUsage: microscheme [-aucvrio] [-m model] [-d device] [-p programmer] [-w filename] [-t rounds] program[.ms]\n\n"
			"Option flags:\n"
			"  -a    Assemble (implied by -u) (requires -m)\n"
			"  -u    Upload (requires -d)\n"
			"  -c    Cleanup (removes intermediate files)\n"
			"  -v    Verbose\n"
			"  -r    Verify (Uploading takes longer)\n"
			"  -i    Allow the same file to be included more than once\n"
			"  -o    Disable optimisations  \n"
			"  -h    Show this help message \n\n"
			"Configuration flags:\n"
			"  -m model       Specify a model (UNO/MEGA/LEO...)\n"
			"  -d device      Specify a physical device\n"
			"  -p programmer  Tell avrdude to use a particular programmer\n"
			"  -w files       'Link' with external C or assembly files\n"
			"  -t rounds      Specify the maximum number of tree-shaker rounds\n";

	while ((c = getopt(argc, argv, "hiaucovrm:d:p:t:w:")) != -1)
	switch (c)	{
		case 'h':	fprintf(stdout, "%s", helpmsg); exit(EXIT_SUCCESS); break;
		case 'i':	opt_includeonce = false;	break;
		case 'u':	opt_upload = true;			
		case 'a':	opt_assemble = true;		break;
		case 'c':	opt_cleanup = true;			break;
		//case 's':	opt_softreset = true;		break;
		case 'o':	opt_aggressive = false;		break;
		case 'v':	opt_verbose = true;			break;
		case 'r':	opt_verify = true;			break;
		case 'm':	model = optarg;				break;
		case 'd':	device = optarg;			break;
		case 'p':   programmer = optarg;		break;
		case 'w':	linkwith = optarg;			break;
		case 't':	treeshaker_max_rounds = atoi(optarg);	break;
		case '?':
			if (optopt == 'm')
				fprintf (stderr, "Option -%c requires an argument.\n", optopt);
			else if (isprint (optopt))
				fprintf (stderr, "Unknown option `-%c'.\n", optopt);
			else
				fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
			return 1;
		default:
			abort ();
	}


	if (argc < 2) {
		fprintf(stdout, "%s", helpmsg);

		return(EXIT_FAILURE);
	}

	inname=argv[optind];

	basename=str_clone(inname);

	#ifdef __WIN32 // Defined for both 32 and 64 bit environments
		char delimit = '\\';
	#else
		char delimit = '/';
	#endif

	if (strrchr(basename, delimit)) {
		shortbase = strrchr(basename, delimit) + 1;
	} else {
		shortbase = basename;
	}

	shortbase[strcspn(shortbase, ".")] = 0;

	outname=str_clone_more(shortbase, 2);
	strcat(outname, ".s");

	if (argc == optind) {
		fprintf(stderr, "No input file.\n");
		exit(EXIT_FAILURE);
	}

	if (argc > optind + 1) {
		fprintf(stderr, "Multiple input files not yet supported.\n");
		exit(EXIT_FAILURE);
	}

	model_info theModel;
	int i;
	bool found = false;
	
	for (i = 0; i<numModels; i++) {
		if (strcmp(models[i].name, model) == 0) {
			theModel = models[i];
			found = true;
		}
	}

	if (!found) {
		fprintf(stderr, "Device not supported.\n");
		return EXIT_FAILURE;
	}







	// This function controls the overall compilation process, which is implemented
	// as four seperate phases, invoked in order.

	// 1) Lex the file
	lexer_tokenNode *root = NULL;

	root = lexer_lexBlob(src_primitives_ms, src_primitives_ms_len, root);

	root = lexer_lexBlob(src_stdlib_ms, src_stdlib_ms_len, root);

	root = lexer_lexFile(inname, root);

	globalIncludeList = try_malloc(sizeof(char*));
	globalIncludeList[0] = str_clone(inname);
	globalIncludeListN = 1;

	// 2) Parse the file
	AST_expr *ASTroot = parser_parseFile(root->children, root->numChildren);

	// (We can free the memory used by the lexer once the parser has finished)...
	lexer_freeTokenTree(root);

	// We set up a global environment:
	globalEnv = try_malloc(sizeof(Environment));
	scoper_initEnv(globalEnv);

	// And hand it to the scoper...
	currentEnvironment = globalEnv;

	// At the top level, there is no 'current closure', and hence no 'current closure environment'
	currentClosureEnvironment = NULL;

	// 3) Scope the file:
	ASTroot = scoper_scopeExpr(ASTroot);

	numPurgedGlobals = -1;
	int latestpurge = -2;
	int rounds = 0;

	if (opt_aggressive) {
		globalEnv->realAddress = try_malloc(sizeof(int) * globalEnv->numBinds);
		int i;
		for (i = 0; i < globalEnv->numBinds; i++) {
			globalEnv->realAddress[i] = 0;
		}

		while ((numPurgedGlobals > latestpurge) && (rounds < treeshaker_max_rounds)) {
			//fprintf(stderr, ">> ROUND %i\n", roundi);
			rounds++;
			latestpurge = numPurgedGlobals;

			treeshaker_shakeExpr(ASTroot);
			treeshaker_purge();

			//fprintf(stderr, ">> Aggressive: %i globals purged!\n", numPurgedGlobals);
		} 

		fprintf(stdout, ">> Treeshaker: After %i rounds: %i globals purged! %i bytes will be reserved.\n", rounds, numPurgedGlobals, numUsedGlobals * 2);

		if (opt_verbose) {
			fprintf(stdout, ">> Remaining globals: [");
			int i;
			for (i = 0; i < globalEnv->numBinds; i++) {
				if (globalEnv->realAddress[i] >= 0)
					fprintf(stdout, "%s ", globalEnv->binding[i]);
			}
			fprintf(stdout, "]\n");
		}

		
	} else {
		numUsedGlobals = globalEnv->numBinds;
	}

	// 4) Generate code. (Starting with some preamble)

	FILE *outputFile;
	outputFile = fopen(outname, "w");

	if (!outputFile) {
		fprintf(stderr, ">> Error! Could not open output file.\n");
		exit(EXIT_FAILURE);
	}

		codegen_emitModelHeader(theModel, outputFile);
		codegen_emitPreamble(outputFile);

		// Next, we recursively emit code for the actual program body:
		codegen_emit(ASTroot, 0, outputFile);

		// Finally, we emit some postamble code
		codegen_emitPostamble(outputFile);

	fclose(outputFile);

	// Finally, the memory allocated during parsing can be freed.
	parser_freeAST(ASTroot);
	freeEnvironment(globalEnv);

	// If we've reached this stage, then everything has gone OK:
	fprintf(stdout, ">> %i lines compiled OK\n", fileLine);

	char cmd[500];

	if (opt_assemble) {
		if (strcmp(model, "") == 0) {
			fprintf(stderr, "Model Not Set. Cannot assemble.\n");
			return EXIT_FAILURE;
		}

		fprintf(stderr, ">> Assembling...\n");
		sprintf(cmd, "avr-gcc -mmcu=%s -o %s.elf %s.s %s", theModel.STR_TARGET, shortbase, shortbase, linkwith);

		try_execute(cmd);

		sprintf(cmd, "avr-objcopy --output-target=ihex %s.elf %s.hex", shortbase, shortbase);
		
		try_execute(cmd);
	}

	// if (opt_softreset && theModel.software_reset) {
	// 	fprintf(stdout, ">> Attempting software reset...\n");
	// 	int fd = -1;
	// 	struct termios options;
		
	// 	tcgetattr(fd, &options);

	// 	cfsetispeed(&options, B1200);
	// 	cfsetospeed(&options, B1200);
		
	// 	options.c_cflag |= (CLOCAL | CREAD | CS8 | HUPCL);
	// 	options.c_cflag &= ~(PARENB | CSTOPB);
		
	// 	tcsetattr(fd, TCSANOW, &options);

	// 	fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
	// 	if (fd == -1) {
	// 		fprintf(stderr, ">> Warning: Unable to open %s for soft reset. (%s)\n", device, strerror(errno));
	// 	} else {
	// 		close(fd);
	// 	}
	// }

	if (opt_upload) {

		if (strcmp(device, "") == 0) {
			fprintf(stderr, "Device Not Set. Cannot upload.\n");
			return EXIT_FAILURE;
		}

		if (strcmp(programmer, "") == 0) {
			programmer = theModel.STR_PROG;
		}

		fprintf(stderr, ">> Uploading...\n");

		char *opt1, *opt2;
		if (opt_verbose) opt1 = "-v"; else opt1 = "";
		if (opt_verify) opt2 = ""; else opt2 = "-V";

		sprintf(cmd, "avrdude %s %s -p %s -P %s -b %s -c %s -D -U flash:w:%s.hex:i", opt1, opt2, theModel.STR_TARGET, device, theModel.STR_BAUD, programmer, shortbase);
		
		try_execute(cmd);
	}

	if (opt_cleanup) {
		fprintf(stdout, ">> Cleaning Up...\n");

		#ifdef __WIN32 // Defined for both 32 and 64 bit environments
			sprintf(cmd, "del %s.s %s.elf %s.hex", shortbase, shortbase, shortbase);
		#else
			sprintf(cmd, "rm -f %s.s %s.elf %s.hex", shortbase, shortbase, shortbase);
		#endif

		try_execute(cmd);
	}

	fprintf(stdout, ">> Finished.\n");

	try_free(basename);
	try_free(outname);

	for (i=0; i<globalIncludeListN; i++)
		try_free(globalIncludeList[i]);

	try_free(globalIncludeList);

	return EXIT_SUCCESS;
}