// Parse a loop body (could also be used for macro body) static void parse_ram_block(int line_number, char* body) { Input_now->line_number = line_number;// set line number to loop start Input_now->src.ram_ptr = body;// set RAM read pointer to loop // Parse loop body Parse_until_eob_or_eof(); if(GotByte != CHAR_EOB) Bug_found("IllegalBlockTerminator", GotByte); }
// Parse or skip a block. Returns whether block's '}' terminator was missing. // Afterwards: GotByte = '}' static bool skip_or_parse_block(bool parse) { if(!parse) { Input_skip_or_store_block(FALSE); return(FALSE); } // if block was correctly terminated, return FALSE Parse_until_eob_or_eof(); // if block isn't correctly terminated, complain and exit if(GotByte != CHAR_EOB) Throw_serious_error(exception_no_right_brace); return(FALSE); }
// Parse a whole source code file void Parse_and_close_file(FILE* fd, const char* filename) { // be verbose if(Process_verbosity > 2) printf("Parsing source file '%s'\n", filename); // set up new input Input_new_file(filename, fd); // Parse block and check end reason Parse_until_eob_or_eof(); if(GotByte != CHAR_EOF) Throw_error("Found '}' instead of end-of-file."); // close sublevel src fclose(Input_now->src.fd); }
// Parse macro call ("+MACROTITLE"). Has to be re-entrant. void Macro_parse_call(void) // Now GotByte = dot or first char of macro name { char local_gotbyte; struct symbol *symbol; struct section new_section, *outer_section; struct input new_input, *outer_input; struct macro *actual_macro; struct rwnode *macro_node, *symbol_node; zone_t macro_zone, symbol_zone; int arg_count = 0; // Enter deeper nesting level // Quit program if recursion too deep. if (--macro_recursions_left < 0) Throw_serious_error("Too deeply nested. Recursive macro calls?"); macro_zone = get_zone_and_title(); // now GotByte = first non-space after title // internal_name = MacroTitle ARG_SEPARATOR (grows to signature) // Accept n>=0 comma-separated arguments before CHAR_EOS. // Valid argument formats are: // EXPRESSION (everything that does NOT start with '~' // ~.LOCAL_LABEL_BY_REFERENCE // ~GLOBAL_LABEL_BY_REFERENCE // now GotByte = non-space if (GotByte != CHAR_EOS) { // any at all? do { // if arg table cannot take another element, enlarge if (argtable_size <= arg_count) enlarge_arg_table(); // Decide whether call-by-reference or call-by-value // In both cases, GlobalDynaBuf may be used. if (GotByte == REFERENCE_CHAR) { // read call-by-reference arg DynaBuf_append(internal_name, ARGTYPE_NUM_REF); GetByte(); // skip '~' character Input_read_zone_and_keyword(&symbol_zone); // GotByte = illegal char arg_table[arg_count].symbol = symbol_find(symbol_zone, 0); } else { // read call-by-value arg DynaBuf_append(internal_name, ARGTYPE_NUM_VAL); ALU_any_result(&(arg_table[arg_count].result)); } ++arg_count; } while (Input_accept_comma()); } // now arg_table contains the arguments // now GlobalDynaBuf = unused // check for "unknown macro" // Search for macro. Do not create if not found. search_for_macro(¯o_node, macro_zone, FALSE); if (macro_node == NULL) { Throw_error("Macro not defined (or wrong signature)."); Input_skip_remainder(); } else { // make macro_node point to the macro struct actual_macro = macro_node->body; local_gotbyte = GotByte; // CAUTION - ugly kluge // set up new input new_input.original_filename = actual_macro->def_filename; new_input.line_number = actual_macro->def_line_number; new_input.source_is_ram = TRUE; new_input.state = INPUTSTATE_NORMAL; // FIXME - fix others! new_input.src.ram_ptr = actual_macro->parameter_list; // remember old input outer_input = Input_now; // activate new input Input_now = &new_input; // remember old section outer_section = Section_now; // start new section (with new zone) // FALSE = title mustn't be freed Section_new_zone(&new_section, "Macro", actual_macro->original_name, FALSE); GetByte(); // fetch first byte of parameter list // assign arguments if (GotByte != CHAR_EOS) { // any at all? arg_count = 0; do { // Decide whether call-by-reference // or call-by-value // In both cases, GlobalDynaBuf may be used. if (GotByte == REFERENCE_CHAR) { // assign call-by-reference arg GetByte(); // skip '~' character Input_read_zone_and_keyword(&symbol_zone); if ((Tree_hard_scan(&symbol_node, symbols_forest, symbol_zone, TRUE) == FALSE) && (pass_count == 0)) Throw_error("Macro parameter twice."); symbol_node->body = arg_table[arg_count].symbol; } else { // assign call-by-value arg Input_read_zone_and_keyword(&symbol_zone); symbol = symbol_find(symbol_zone, 0); // FIXME - add a possibility to symbol_find to make it possible to find out // whether symbol was just created. Then check for the same error message here // as above ("Macro parameter twice."). symbol->result = arg_table[arg_count].result; } ++arg_count; } while (Input_accept_comma()); } // and now, finally, parse the actual macro body Input_now->state = INPUTSTATE_NORMAL; // FIXME - fix others! // maybe call parse_ram_block(actual_macro->def_line_number, actual_macro->body) Input_now->src.ram_ptr = actual_macro->body; Parse_until_eob_or_eof(); if (GotByte != CHAR_EOB) Bug_found("IllegalBlockTerminator", GotByte); // end section (free title memory, if needed) Section_finalize(&new_section); // restore previous section Section_now = outer_section; // restore previous input: Input_now = outer_input; // restore old Gotbyte context GotByte = local_gotbyte; // CAUTION - ugly kluge Input_ensure_EOS(); } ++macro_recursions_left; // leave this nesting level }