Beispiel #1
0
char* find_python_home_from_shebang(const char* filename, char* buffer) {
    char* dir_ptr = NULL;
    char* ptr = buffer;
    char* eol = strchr(buffer, '\n');
    /* This checks if we have a shebang line, also because of short-circuiting it works with a buffer size 0 and 1. */
    if (eol == NULL || ptr[0] != '#' || ptr[1] != '!') {
        error("cannot find shebang line in file '%s'", filename);
    }

    if (*(eol - 1) == '\r') { /* We know eol - ptr > 2 */
        eol--;
    }

    ptr += 2; /* skip the #! */

    /* skip quotes if there are any */
    if (*ptr == '"') {
        ++ptr;
        eol = (char*) memchr(ptr, '"', eol - ptr);
        if (eol == NULL) {
            error("cannot find the end of the quotes ('\"') in the shebang line of file '%s'", filename);
        }
    } else {
        /* find the first space and stop there */
        char* eos = (char*) memchr(ptr, ' ', eol - ptr);
        if (eos != NULL) {
            eol = eos;
        }
    }

    dir_ptr = str_back_path(ptr, eol);
    if (dir_ptr == NULL || dir_ptr == ptr) {
        /* the shebang line was something like: #!python.exe or #!\python.exe */
        return str_clone("python home path", "");
    }

    /* skip the bin/ part of the path */
    dir_ptr = str_back_path(ptr, dir_ptr - 1);
    if (dir_ptr == NULL || dir_ptr == ptr) {
        /* the shebang line was something like: #!bin\python.exe or #!\bin\python.exe */
        return str_clone("python home path", "");
    }

    {
        char* result = (char*) myalloc("python home path", dir_ptr - ptr + 1);
        strncpy(result, ptr, dir_ptr - ptr);
        result[dir_ptr - ptr] = '\x00'; /* always put null at the end because strncpy doesn't necessarily do so */
        return result;
    }
}
Beispiel #2
0
struct mapnode * map_put(t_map map, const char *key, void * data){
	struct mapnode * node = map_get(map, key);
	if(!node){
		node = (struct mapnode*)link_addnew((t_link)map, sizeof(struct mapnode));
		node->key = str_clone(key);
	}
	node->data = data;
	return node;
}
Beispiel #3
0
char * replace(const char * str, const char * pat, const char * rep)
{
    if (!str || !pat || !rep) {
        if (!str) {
            return NULL;
        } else {
            return str_clone(str);
        }
    }

    int str_len = (int) strlen(str);
    int pat_len = (int) strlen(pat);
    if (pat_len == 0) {
        return str_clone(str);
    }
    int rep_len = (int) strlen(rep);

    int * next = get_next(pat, pat_len);

    char * buffer = new char[(str_len/pat_len + 1) * rep_len + 1];
    int b = 0;
    int i = 0, p = 0;
    while ((p = match(str, i, pat, next, pat_len)) != -1) {
        strncpy(buffer + b, str + i, p - i);
        b += (p-i);
        strncpy(buffer + b, rep, rep_len);
        b += rep_len;
        i = p + pat_len;
    }

    strncpy(buffer + b, str + i, str_len - i);
    b += (str_len - i);
    buffer[b] = 0;

    delete[] next;

    char * new_str = new char[b + 1];
    strcpy(new_str, buffer);
    delete[] buffer;
    return new_str;
}
Beispiel #4
0
//#######################################################################################
bool _put_roll_string(tDisplay *pDisplay, graphic_strings_t *StringsStruct)
{
	if(!StringsStruct->TimerInitialized)
	{
		StringsStruct->TimerInitialized = true;
		if(!StringsStruct->TimerScrollInterval) StringsStruct->TimerScrollInterval = 1000;
		timer_interval(&StringsStruct->TimerScroll, StringsStruct->TimerScrollInterval);
	}
	bool Return = true;
	tRectangle sClipRegion;
	sClipRegion = pDisplay->sClipRegion;
	pDisplay->sClipRegion = StringsStruct->sClipRegion;
	if(!StringsStruct->WordWrap && timer_tick(&StringsStruct->TimerScroll))
	{
		if(StringsStruct->X_Location + StringsStruct->string_width_get_function(pDisplay, StringsStruct->pFont, StringsStruct->Str->text, -1) < pDisplay->sClipRegion.sXMin)
		{
			StringsStruct->X_Location =  StringsStruct->sClipRegion.sXMin;
			Return = false;
		}
		if(Return)
		{
			
			pDisplay->lcd_func.put_rectangle(pDisplay, pDisplay->sClipRegion.sXMin, pDisplay->sClipRegion.sYMin, pDisplay->sClipRegion.sXMax, pDisplay->sClipRegion.sYMax, true, StringsStruct->Background_Color);
			print_string_properties properties;
			memset(&properties, 0, sizeof(print_string_properties));
			properties.pDisplay = pDisplay;
			properties.pFont = StringsStruct->pFont;
			properties.pcString = str_clone(properties.pcString, StringsStruct->Str);
			//properties.pcString = StringsStruct->Str;
			properties.lLength = -1;
			properties.foreground_color = StringsStruct->Foreground_Color;
			properties.background_color = StringsStruct->Background_Color;
			properties.ulOpaque = StringsStruct->ulOpaque;
			properties.ulVisible = StringsStruct->ulVisible;
			properties.WordWrap = StringsStruct->WordWrap;
			properties.lX = StringsStruct->X_Location;
			properties.lY = StringsStruct->Y_Location;
			properties._SelStart = 0;
			properties._SelLen = 0;
			pDisplay->lcd_func.put_string(&properties);
			pDisplay->lcd_func.box_cache_clean(pDisplay, pDisplay->sClipRegion.sXMin, pDisplay->sClipRegion.sYMin, pDisplay->sClipRegion.sXMax, pDisplay->sClipRegion.sYMax);
			StringsStruct->X_Location--;
		}
	}
	//else
	//{
	//	put_rectangle(pDisplay, pDisplay->sClipRegion.sXMin, pDisplay->sClipRegion.sYMin, pDisplay->sClipRegion.sXMax, pDisplay->sClipRegion.sYMax, true, StringsStruct->Background_Color);
	//	StringsStruct->print_function(pDisplay, StringsStruct->pFont, Text, -1, StringsStruct->Foreground_Color, StringsStruct->Background_Color, StringsStruct->ulOpaque, StringsStruct->ulVisible, StringsStruct->WordWrap, StringsStruct->X_Location, StringsStruct->Y_Location, 0, 0);
	//	box_cache_clean(pDisplay, pDisplay->sClipRegion.sXMin, pDisplay->sClipRegion.sYMin, pDisplay->sClipRegion.sXMax, pDisplay->sClipRegion.sYMax);
	//}
	pDisplay->sClipRegion = sClipRegion;
	return Return;
}
Beispiel #5
0
int var_set(const char *name, t_var val){
	int i;
	for (i = 0; i < MAX_VAR_SIZE; ++i){
		if (!var_names[i]){
			// add
			var_names[i] = str_clone(name);
			var_vals[i] = val;
			return i;
		}
		if (strcmp(var_names[i], name) == 0){
			// update
			var_vals[i] = val;
			return i;
		}
	}
	return -1;
}
Beispiel #6
0
int main(int argc, char const *argv[]) {
    /* str_new */
    str_t string = str_new();
    /* str_set */
    str_set(string, "   %d%d%d", 1, 2, 3);
    /* str_append */
    str_append(string, "appending   end");
    /* str_println */
    str_println(string);
    /* str_reverse */
    str_reverse(string);
    str_println(string);
    /* str_length */
    printf("size before trimming:\t%zu\n", str_length(string));
    /* str_trim */
    str_trim(string);
    printf("size after trimming:\t%zu\n", str_length(string));
    /* str_substr */
    str_t substr = str_substr(string, 0, 3);
    printf("substr before swap:\t");
    str_println(substr);
    printf("string before swap:\t");
    str_println(string);
    str_swap(substr, string);
    printf("substr after swap:\t");
    str_println(substr);
    printf("string after swap:\t");
    str_println(string);
    printf("is string empty?\t%s\n",
           str_isempty(string) ? "Yes" : "No");
    printf("is substr equal to string?\t%s\n",
           str_compare(substr, string) ? "No" : "Yes");

    /* str_readFromFile */
    str_readFromFile(string, "neostring.c");
    printf("string size: %zu\t", str_length(string));
    printf("string capacity: %zu\n", string->capacity);
    str_set(string, "ok");
    printf("Before trimToSize():\n");
    printf("string size: %zu\t", str_length(string));
    printf("string capacity: %zu\n", string->capacity);
    /* str_trimToSize */
    str_trimToSize(string);
    printf("After trimToSize():\n");
    printf("string size: %zu\t", str_length(string));
    printf("string capacity: %zu\n", string->capacity);
    str_set(string, "hello, world");
    str_println(string);
    printf("%zu\n", string->size);
    printf("string has prefix ello?\t%s\n", str_hasPrefix(string, "ello") ? "Yes" : "No");
    printf("%zu\n", string->size);
    printf("string has suffix orld?\t%s\n", str_hasSuffix(string, "orld") ? "Yes" : "No");
    /* str_clone */
    str_t clone = str_clone(string);
    /* str_toupper */
    str_toupper(clone);
    /* str_writeToFile */
    str_writeToFile(clone, "./test.txt");
    /* str_destroy */
    str_destroy(string);
    str_destroy(clone);
    str_destroy(substr);
    return 0;
}
Beispiel #7
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;
}
Beispiel #8
0
/*------------------------------------------------------------*/
static regexp *
compile_regexp (const char *str)
{
  regexp *pat;
  char *pattern = NULL;

  if (current_state->regularexpression) {
    pattern = str_clone (str);

  } else {			/* translate into regular expression */
    int pattern_size = 128;
    char *s, *p;

  start_again:
    if (pattern != NULL) free (pattern);
    pattern_size *= 2;
    pattern = malloc ((pattern_size + 1) * sizeof (char));

    s = (char *) str;
    p = pattern;
    *p++ = '^';

    while (*s != '\0') {
      switch (*s) {

      case '*':			/* any number of any characters */
	if ((p - pattern + 1) >= (pattern_size - 1)) goto start_again;
	*p++ = '.';
	*p++ = '*';
	break;

      case '%':			/* any single character */
	if (p - pattern >= (pattern_size - 1)) goto start_again;
	*p++ = '.';
	break;

      case '#':			/* any number of any digits */
	if ((p - pattern + 5) >= (pattern_size - 1)) goto start_again;
	*p++ = '[';
	*p++ = '0';
	*p++ = '-';
	*p++ = '9';
	*p++ = ']';
	*p++ = '*';
	break;

      case '+':			/* any single digit */
	if ((p - pattern + 4) >= (pattern_size - 1)) goto start_again;
	*p++ = '[';
	*p++ = '0';
	*p++ = '-';
	*p++ = '9';
	*p++ = ']';
	break;

      case '^':			/* special meaning in regular expression */
      case '$':
      case '[':
      case ']':
      case '.':
	if (p - pattern + 1 >= (pattern_size - 1)) goto start_again;
	*p++ = '\\';
	*p++ = *s;
	break;

      default:			/* ordinary character */
	if (p - pattern >= (pattern_size - 1)) goto start_again;
	*p++ = *s;
	break;
      }
      s++;
    }

    *p++ = '$';
    *p = '\0';
  }

  pat = regcomp (pattern);
  free (pattern);
  if (pat == NULL) yyerror ("invalid regular expression");
  return pat;
}
Beispiel #9
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;
}