VM * VM_fromBytecode (FILE *stream) { int glob_c, prog_len, i; Program *p; VM *vm; if (fscanf (stream, "%d:%d", &glob_c, &prog_len) < 2) { fprintf (stderr, "Bytecode format error\n" "Expected glob_count:prog_size:opcode1:...:opcodeN\n"); exit (EXIT_FAILURE); } p = Program_new (prog_len); vm = VM_new (p, glob_c); Program_destroy (p); for (i = 0; i < prog_len; i++) { if (fscanf (stream, ":%d", &vm->mem[i]) < 1) { fprintf (stderr, "Bytecode format error\n" "Expected glob_count:prog_size:opcode1:...:opcodeN\n"); exit (EXIT_FAILURE); } } return vm; }
/* a helper function to clean up the program before exit */ void cleanup_sish(void) { /* close open history file */ if (fclose(historyptr) != 0) { printerr(debugLevel, "fail to close the history file\n"); return; } /* delete history file */ if (remove(historyfilename) != 0) { printerr(debugLevel, "fail to delete the history file\n"); return; } /* close open batch file */ if (fflag) { if (fclose(batchfileptr) != 0) { printerr(debugLevel, "fail to close the batch file\n"); return; } } /* free string variables */ assert(shellpath != NULL); free(shellpath); /* free the memory space for the array storing local variables */ destroy_localVar(); /* free created program structs */ for (int i = 0; i < MAXNUMOFPROS; i++) { if (programs[i] != NULL) { Program_destroy(programs[i]); } } }
/* unit testing */ int main(int argc, char *argv[]) { /* parsecml test */ printf("\nparsecml test:\n"); parsecml(argc - 1, argv + 1); printf("dflag: %d\n", dflag); printf("xflag: %d\n", xflag); printf("fflag: %d\n", fflag); printf("debugLevel: %d\n", debugLevel); printf("filename: %s\n", batchfile); for (int i = 0; filearg[i] != NULL; i++) { printf("filearg[%d]: %s\n", i, filearg[i]); } /* printerr test */ printf("\n\nprinterr test:\n\n"); char *errorstr = "This is an error"; printerr(debugLevel, errorstr); /* program struct test */ printf("\nprogram struct test:\n"); char *test_argv[3]; test_argv[0] = "myprog"; test_argv[1] = "arg1"; test_argv[2] = "arg2"; Program *p = Program_create(3, test_argv, 1, 1, "F2", "F1"); Program_print(p); Program_destroy(p); /* tokcml test */ printf("\ntolcml test:\n"); char *input = "ls -alg | wc | cat | more"; char **tokens; tokcml(input, &tokens); for (int i = 0; tokens[i] != NULL; i++) { printf("tokens[%d]: %s\n", i, tokens[i]); } /* pipe setter and getter test */ printf("\npipesetter and getter test:\n"); setNumOfPipes(tokens); printf("The number of pipes is: %d\n", getNumOfPipes()); /* arguments reader test */ printf("\narguments reader test 1:\ninput: %s\n", input); getArgs(tokens); for (int i = 0; programs[i] != NULL; i++) { Program_print(programs[i]); } token_destroy(tokens); /* arguments reader test 2 */ input = "myprog arg1 arg2 < F1 > F2"; printf("\narguments reader test 2:\ninput: %s\n", input); tokcml(input, &tokens); setNumOfPipes(tokens); getArgs(tokens); for (int i = 0; programs[i] != NULL; i++) { Program_print(programs[i]); } token_destroy(tokens); /* arguments reader test 3 */ input = "< F1 > F2 myprog arg1 arg2"; printf("\narguments reader test 3:\ninput: %s\n", input); tokcml(input, &tokens); setNumOfPipes(tokens); getArgs(tokens); for (int i = 0; programs[i] != NULL; i++) { Program_print(programs[i]); } token_destroy(tokens); /* arguments reader test 4 */ input = "< F1 myprog arg1 arg2 > F2"; printf("\narguments reader test 4:\ninput: %s\n", input); tokcml(input, &tokens); setNumOfPipes(tokens); getArgs(tokens); for (int i = 0; programs[i] != NULL; i++) { Program_print(programs[i]); } token_destroy(tokens); /* arguments reader test 5 */ input = "prog1 arg1 arg2 | prog2 | prog3 arg1"; printf("\narguments reader test 5:\ninput: %s\n", input); tokcml(input, &tokens); setNumOfPipes(tokens); getArgs(tokens); for (int i = 0; programs[i] != NULL; i++) { Program_print(programs[i]); } token_destroy(tokens); /* arguments reader test 6 */ input = "prog1 arg1"; printf("\narguments reader test 6:\ninput: %s\n", input); tokcml(input, &tokens); setNumOfPipes(tokens); getArgs(tokens); for (int i = 0; programs[i] != NULL; i++) { Program_print(programs[i]); } token_destroy(tokens); /* clean up */ for (int i = 0; i < MAXNUMOFPROS; i++) { if (programs[i] != NULL) { Program_destroy(programs[i]); } } }
int main (int argc, char* argv[]) { int i = 1; FILE *alvcin = NULL; Node *ast = NULL; SymTable *st = NULL; Program *p = NULL; int exit_status = EXIT_SUCCESS; struct { enum { COMPILE, EXEC, BYTECODE, TRACE } mode; char *out, *in; } options = { COMPILE, NULL, NULL }; progname = basename (argv[0]); if (!(argc == 2 && arg("-h")) && argc < 3) fatal ("not enough arguments (run with -h)"); if (arg("-h")) { puts ( "alvc -- the Awesome L Virtual machine and Compiler\n" " usage: alvc mode input [output]\n" " mode: may be either -c (compile), -x (execute),\n" " -b (execute bytecode), -t (trace) ou -h (help)\n" " input: input file in L or in bytecode\n" " output: output file, defaults to /dev/stdout (only for -c/-t)" ); exit (EXIT_SUCCESS); } else if (arg("-c")) options.mode = COMPILE; else if (arg("-x")) options.mode = EXEC; else if (arg("-b")) options.mode = BYTECODE; else if (arg("-t")) options.mode = TRACE; else fatal ("unknwon mode"); yyfile = argv[++i]; options.in = yyfile; if (argv[++i]) options.out = argv[i]; alvcin = fopen (options.in, "r"); if (NULL == alvcin) { fprintf (stderr, "unable to open %s for reading (%s)\n", options.in, strerror (errno)); exit (errno); } yyin = alvcin; if (EXEC != options.mode && BYTECODE != options.mode && NULL != options.out) { stdout = freopen (options.out, "w+", stdout); if (NULL == stdout) { fprintf (stderr, "unable to open %s for writing (%s)\n", options.out, strerror (errno)); exit (errno); } } if (options.mode != BYTECODE) { next_token (); ast = rule_program (); st = SymTable_new ( Node_countType (ast, N_VAR_DEC) + Node_countType (ast, N_FUN_DEC) + Node_countType (ast, N_ARR_DEC) ); SymTable_build (st, ast); if (SymTable_hasFailed (false)) exit(EXIT_FAILURE); p = AST_compile (ast, st); } switch (options.mode) { case COMPILE: Program_dump (p, st); break; case EXEC: runvm (VM_new (p, SymTable_globalSize (st)), p, &exit_status); break; case BYTECODE: { VM *vm = VM_fromBytecode (alvcin); runvm (vm, (p = VM_extractProgram (vm)), &exit_status); } break; case TRACE: SymTable_print (st); Program_print (p); break; } if (NULL != p) Program_destroy (p); if (NULL != st) SymTable_destroy (st); if (NULL != ast) Node_destroy (ast); fclose (alvcin); exit (exit_status); }