int main(int argc, char *argv[]) { clock_t rdp_finish_time, rdp_start_time = clock(); int rdp_symbol_statistics = 0, /* show symbol_ table statistics flag */ rdp_line_echo_all = 0, /* make a listing on all passes flag */ rdp_filter = 0, /* filter flag */ rdp_line_echo = 0, /* make listing flag */ rdp_lexicalise = 0; /* print lexicalised output flag */ unsigned long rdp_textsize = 35000l; /* size of scanner text array */ unsigned long rdp_tabwidth = 8l; /* tab expansion width */ char* rdp_vcg_filename = NULL; /* filename for -V option */ rdp_tree_node_data* rdp_tree = (rdp_tree_node_data*) graph_insert_graph("RDP derivation tree"); /* hook for derivation tree */ rdp_tree_node_data* rdp_tree_root; arg_message("Minitree compiler V1.50 (c) Adrian Johnstone 1997\n" RDP_STAMP "\n\n""Usage: minitree [options] source[.m]"); arg_message(""); arg_boolean('f', "Filter mode (read from stdin and write to stdout)", &rdp_filter); arg_boolean('l', "Make a listing", &rdp_line_echo); arg_boolean('L', "Print lexicalised source file", &rdp_lexicalise); arg_string ('o', "Write output to filename", &rdp_outputfilename); arg_boolean('s', "Echo each scanner symbol as it is read", &rdp_symbol_echo); arg_boolean('S', "Print summary symbol table statistics", &rdp_symbol_statistics); arg_numeric('t', "Tab expansion width (default 8)", &rdp_tabwidth); arg_numeric('T', "Text buffer size in bytes for scanner (default 20000)", &rdp_textsize); arg_boolean('v', "Set verbose mode", &rdp_verbose); arg_string ('V', "Write derivation tree to filename in VCG format", &rdp_vcg_filename); rdp_sourcefilenames = arg_process(argc, argv); /* Fix up filetypes */ for (rdp_sourcefilenumber = 0; rdp_sourcefilenames[rdp_sourcefilenumber] != NULL; rdp_sourcefilenumber++) rdp_sourcefilenames[rdp_sourcefilenumber] = text_default_filetype(rdp_sourcefilenames[rdp_sourcefilenumber], "m"); if (rdp_filter) { rdp_sourcefilenames[0] = "-"; rdp_outputfilename = "-"; rdp_sourcefilenames[1] = NULL; /* make sure no further filenames are taken from the array */ } if ((rdp_sourcefilename = rdp_sourcefilenames[0]) == NULL) arg_help("no source files specified"); if (rdp_sourcefilenames[1] != NULL) text_message(TEXT_FATAL, "multiple source files not allowed\n"); text_init(rdp_textsize, 25, 100, (int) rdp_tabwidth); scan_init(0, 0, 0, rdp_symbol_echo, rdp_tokens); if (rdp_lexicalise) scan_lexicalise(); mini = symbol_new_table("mini", 101, 31, symbol_compare_string, symbol_hash_string, symbol_print_string); rdp_set_initialise(); rdp_load_keywords(); if (rdp_verbose) text_printf("\nMinitree compiler V1.50 (c) Adrian Johnstone 1997\n" RDP_STAMP "\n\n"); for (rdp_pass = 1; rdp_pass <= RDP_PASSES; rdp_pass++) { rdp_tree_update = rdp_pass == RDP_PASSES; text_echo(rdp_line_echo_all || (rdp_line_echo && rdp_pass == RDP_PASSES)); for (rdp_sourcefilenumber = 0; (rdp_sourcefilename = rdp_sourcefilenames[rdp_sourcefilenumber]) != NULL; rdp_sourcefilenumber++) { if (text_open(rdp_sourcefilename) == NULL) arg_help("unable to open source file"); text_get_char(); scan_(); program(rdp_tree_root = rdp_add_node("program", rdp_tree)); /* call parser at top level */ if (text_total_errors() != 0) text_message(TEXT_FATAL, "error%s detected in source file ''\n", text_total_errors() == 1 ? "" : "s", rdp_sourcefilename); /* crash quietly */ graph_epsilon_prune_rdp_tree(rdp_tree_root, sizeof(rdp_tree_edge_data)); } } rdp_sourcefilename = rdp_sourcefilenames[0]; /* Reset filename to first file in the list */ graph_set_root(rdp_tree, rdp_tree_root); if (rdp_vcg_filename != NULL) { FILE *rdp_vcg_file; if (*rdp_vcg_filename == '\0') /* No filename supplied */ rdp_vcg_filename = "rdparser"; rdp_vcg_file = fopen((rdp_vcg_filename = text_default_filetype(rdp_vcg_filename, "vcg")), "w"); if (rdp_vcg_file == NULL) text_message(TEXT_FATAL, "unable to open VCG file '%s' for write\n", rdp_vcg_filename); if (rdp_verbose) text_message(TEXT_INFO, "Dumping derivation tree to VCG file '%s'\n", rdp_vcg_filename); text_redirect(rdp_vcg_file); graph_vcg(rdp_tree, NULL, scan_vcg_print_node, scan_vcg_print_edge); text_redirect(stdout); fclose(rdp_vcg_file); } code_generate(rdp_sourcefilename, rdp_outputfilename, rdp_tree); if (rdp_symbol_statistics) { symbol_print_all_table_statistics(11); symbol_print_all_table(); } text_print_total_errors(); if (rdp_verbose) { rdp_finish_time = clock(); text_message(TEXT_INFO, "%.3f CPU seconds used\n", ((double) (rdp_finish_time-rdp_start_time)) / CLOCKS_PER_SEC); } return rdp_error_return; }
static void parse_switch_spec(assembly_operand switch_value, int label, int action_switch) { int i, j, label_after = -1, spec_sp = 0; int max_equality_args = ((!glulx_mode) ? 3 : 1); sequence_point_follows = FALSE; do { if (spec_sp == 32) { error("At most 32 values can be given in a single 'switch' case"); panic_mode_error_recovery(); return; } if (action_switch) { get_next_token(); if (token_type == SQ_TT || token_type == DQ_TT) { ebf_error("action (or fake action) name", token_text); continue; } spec_stack[spec_sp] = action_of_name(token_text); if (spec_stack[spec_sp].value == -1) { spec_stack[spec_sp].value = 0; ebf_error("action (or fake action) name", token_text); } } else spec_stack[spec_sp] = code_generate(parse_expression(CONSTANT_CONTEXT), CONSTANT_CONTEXT, -1); misc_keywords.enabled = TRUE; get_next_token(); misc_keywords.enabled = FALSE; spec_type[spec_sp++] = switch_sign(); switch(spec_type[spec_sp-1]) { case 0: if (action_switch) ebf_error("',' or ':'", token_text); else ebf_error("',', ':' or 'to'", token_text); panic_mode_error_recovery(); return; case 1: goto GenSpecCode; case 3: if (label_after == -1) label_after = next_label++; } } while(TRUE); GenSpecCode: if ((spec_sp > max_equality_args) && (label_after == -1)) label_after = next_label++; if (label_after == -1) { compile_alternatives(switch_value, spec_sp, 0, label, FALSE); return; } for (i=0; i<spec_sp;) { j=i; while ((j<spec_sp) && (spec_type[j] != 3)) j++; if (j > i) { if (j-i > max_equality_args) j=i+max_equality_args; if (j == spec_sp) compile_alternatives(switch_value, j-i, i, label, FALSE); else compile_alternatives(switch_value, j-i, i, label_after, TRUE); i=j; } else { if (!glulx_mode) { if (i == spec_sp - 2) { assemblez_2_branch(jl_zc, switch_value, spec_stack[i], label, TRUE); assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1], label, TRUE); } else { assemblez_2_branch(jl_zc, switch_value, spec_stack[i], next_label, TRUE); assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1], label_after, FALSE); assemble_label_no(next_label++); } } else { if (i == spec_sp - 2) { assembleg_2_branch(jlt_gc, switch_value, spec_stack[i], label); assembleg_2_branch(jgt_gc, switch_value, spec_stack[i+1], label); } else { assembleg_2_branch(jlt_gc, switch_value, spec_stack[i], next_label); assembleg_2_branch(jle_gc, switch_value, spec_stack[i+1], label_after); assemble_label_no(next_label++); } } i = i+2; } } assemble_label_no(label_after); }
void parse_program(char *filename) { printf("parsing file: %s\n", filename); yyfiles = list_new(NULL, &free); log_assert(yyfiles); list_push_back(yyfiles, filename); yyclibs = list_new(NULL, &free); log_assert(yyclibs); yyincludes = hasht_new(8, true, NULL, NULL, NULL); log_assert(yyincludes); /* open file for lexer */ yyin = fopen(filename, "r"); if (yyin == NULL) log_error("could not open input file: %s", filename); /* push buffer state for lexer */ yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE)); /* setup yytypes table for lexer */ yytypes = hasht_new(8, true, NULL, NULL, &free_typename); log_assert(yytypes); /* reset library flags */ libs.usingstd = false; libs.cstdlib = false; libs.cmath = false; libs.ctime = false; libs.cstring = false; libs.fstream = false; libs.iostream = false; libs.string = false; libs.iomanip = false; log_debug("invoking Bison"); int result = yyparse(); if (result != 0) exit(2); /* print syntax tree */ if (arguments.tree) tree_traverse(yyprogram, 0, &print_tree, NULL, NULL); /* initialize scope stack */ log_debug("setting up for semantic analysis"); yyscopes = list_new(NULL, NULL); log_assert(yyscopes); struct hasht *global = hasht_new(32, true, NULL, NULL, &symbol_free); log_assert(global); list_push_back(yyscopes, global); /* build the symbol tables */ log_debug("populating symbol tables"); region = GLOBE_R; offset = 0; symbol_populate(yyprogram); log_debug("global scope had %zu symbols", hasht_used(global)); /* constant symbol table put in front of stack for known location */ struct hasht *constant = hasht_new(32, true, NULL, NULL, &symbol_free); log_assert(constant); list_push_front(yyscopes, constant); region = CONST_R; offset = 0; log_debug("type checking"); type_check(yyprogram); /* generating intermediate code */ log_debug("generating intermediate code"); yylabels = 0; /* reset label counter */ code_generate(yyprogram); struct list *code = ((struct node *)yyprogram->data)->code; /* iterate to get correct size of constant region */ size_t string_size = 0; for (size_t i = 0; i < constant->size; ++i) { struct hasht_node *slot = constant->table[i]; if (slot && !hasht_node_deleted(slot)) { struct typeinfo *v = slot->value; if (v->base == FLOAT_T) string_size += 8; else if (v->base == CHAR_T && v->pointer) string_size += v->token->ssize; } } /* print intermediate code file if debugging */ if (arguments.debug) { char *output_file; asprintf(&output_file, "%s.ic", filename); FILE *ic = fopen(output_file, "w"); if (ic == NULL) log_error("could not save to output file: %s", output_file); fprintf(ic, ".file \"%s\"\n", filename); /* print .string region */ fprintf(ic, ".string %zu\n", string_size); /* iterate to print everything but ints, chars, and bools */ for (size_t i = 0; i < constant->size; ++i) { struct hasht_node *slot = constant->table[i]; if (slot && !hasht_node_deleted(slot)) { struct typeinfo *v = slot->value; if (v->base == FLOAT_T || (v->base == CHAR_T && v->pointer)) { fprintf(ic, " "); print_typeinfo(ic, slot->key, v); fprintf(ic, "\n"); } } } /* print .data region */ fprintf(ic, ".data\n"); for (size_t i = 0; i < global->size; ++i) { struct hasht_node *slot = global->table[i]; if (slot && !hasht_node_deleted(slot)) { struct typeinfo *value = slot->value; if (value->base != FUNCTION_T) { fprintf(ic, " "); print_typeinfo(ic, slot->key, value); fprintf(ic, "\n"); } } } fprintf(ic, ".code\n"); print_code(ic, code); fclose(ic); free(output_file); } log_debug("generating final code"); /* copy because Wormulon */ char *copy = strdup(filename); char *base = basename(copy); free(copy); char *output_file; asprintf(&output_file, "%s.c", base); FILE *fc = fopen(output_file, "w"); if (fc == NULL) log_error("could not save to output file: %s", output_file); time_t t = time(NULL); struct tm *local = localtime(&t); char timestamp[60]; strftime(timestamp, sizeof(timestamp), "%F %T", local); fprintf(fc, "/*\n"); fprintf(fc, " * %s - 120++ Three-Address C Code\n", output_file); fprintf(fc, " * Generated @ %s\n", timestamp); fprintf(fc, " *\n"); fprintf(fc, " * Created by Andrew Schwartzmeyer's 120++ Compiler\n"); fprintf(fc, " * Project located @ https://github.com/andschwa/uidaho-cs445\n"); fprintf(fc, " */\n\n"); fprintf(fc, "/* Required includes for TAC-C */\n"); fprintf(fc, "#include <stdlib.h>\n"); fprintf(fc, "#include <stdbool.h>\n"); fprintf(fc, "#include <string.h>\n"); if (libs.usingstd && libs.iostream) fprintf(fc, "#include <stdio.h>\n"); fprintf(fc, "\n"); /* include passed-through C headers */ fprintf(fc, "/* Source-file C headers */\n"); struct list_node *iter = list_head(yyclibs); while (!list_end(iter)) { fprintf(fc, "#include %s\n", (char *)iter->data); iter = iter->next; } fprintf(fc, "\n"); /* get maximum param size for faux stack */ size_t max_param_size = 0; iter = list_head(code); while (!list_end(iter)) { struct op *op = iter->data; if (op->code == PROC_O) { size_t param_size = op->address[0].offset; if (param_size > max_param_size) max_param_size = param_size; } iter = iter->next; } fprintf(fc, "/* Memory regions */\n"); fprintf(fc, "char constant[%zu];\n", string_size); fprintf(fc, "char global[%zu];\n", global->size); fprintf(fc, "char stack[%zu];\n", max_param_size); fprintf(fc, "\n"); fprintf(fc, "/* Final Three-Address C Generated Code */\n"); final_code(fc, code); fclose(fc); /* remove TAC-C "assembler" code */ if (!arguments.assemble) { /* compile object files */ char *command; asprintf(&command, "gcc -c %s", output_file); int status = system(command); if (status != 0) log_error("command failed: %s", command); remove(output_file); } free(output_file); /* clean up */ log_debug("cleaning up"); tree_free(yyprogram); yylex_destroy(); hasht_free(yytypes); free(yyincludes); /* values all referenced elsewhere */ list_free(yyfiles); list_free(yyclibs); list_free(yyscopes); }