diff --git a/src/_riscos.c b/src/_riscos.c index ddd1810..5819ef5 100644 --- a/src/_riscos.c +++ b/src/_riscos.c @@ -10,7 +10,7 @@ #include #include // for strlen and memmove #include -#include "input.h" // for input_now->location.plat_filename +#include "input.h" // for input_get_location() // constants @@ -124,12 +124,15 @@ void RISCOS_set_filetype(const char *filename, int file_type) // throwback protocol: "type" can be 0, 1 or 2 (DDEUtils message types) void RISCOS_throwback(const char *message, int type) { + struct location location; _kernel_swi_regs regs; // only use throwback protocol if wanted if ((RISCOS_flags & RISCOSFLAG_THROWBACK) == 0) return; + input_get_location(&location); + // if this is the first throwback, set it up and send info if ((RISCOS_flags & RISCOSFLAG_THROWN) == 0) { RISCOS_flags |= RISCOSFLAG_THROWN; @@ -137,14 +140,14 @@ void RISCOS_throwback(const char *message, int type) regs.r[0] = 0; regs.r[1] = 0; // regs.r[2] = (int) toplevel_source; - regs.r[2] = (int) input_now->location.plat_filename; + regs.r[2] = (int) location.plat_filename; _kernel_swi(XDDEUTILS_THROWBACKSEND, ®s, ®s); } // send throwback message regs.r[0] = 1; regs.r[1] = 0; - regs.r[2] = (int) input_now->location.plat_filename; - regs.r[3] = input_now->location.line_number; + regs.r[2] = (int) location.plat_filename; + regs.r[3] = location.line_number; regs.r[4] = type; regs.r[5] = (int) message; _kernel_swi(XDDEUTILS_THROWBACKSEND, ®s, ®s); diff --git a/src/acme.c b/src/acme.c index 53510ad..71e907b 100644 --- a/src/acme.c +++ b/src/acme.c @@ -348,8 +348,10 @@ static void perform_pass(void) pass.warning_count = 0; // Process toplevel files for (ii = 0; ii < toplevel_src_count; ++ii) { - if ((fd = fopen(toplevel_sources_plat[ii], FILE_READBINARY))) { - parse_and_close_platform_file(fd, toplevel_sources_plat[ii]); + fd = fopen(toplevel_sources_plat[ii], FILE_READBINARY); + if (fd) { + parse_source_code_file(fd, toplevel_sources_plat[ii]); + fclose(fd); } else { fprintf(stderr, "Error: Cannot open toplevel file \"%s\".\n", toplevel_sources_plat[ii]); if (toplevel_sources_plat[ii][0] == '-') diff --git a/src/config.h b/src/config.h index 4270b04..a3edeea 100644 --- a/src/config.h +++ b/src/config.h @@ -26,6 +26,12 @@ struct location { const char *plat_filename; // filename in platform style int line_number; }; +// struct for code blocks (loop conditions, loop bodies and macro bodies) +struct block { + int line_number; // start of block + char *body; +}; + // stuff for results from expression parser: diff --git a/src/flow.c b/src/flow.c index 734769c..675483d 100644 --- a/src/flow.c +++ b/src/flow.c @@ -55,7 +55,7 @@ static void parse_ram_block(struct block *block) { // set line number to loop start // set RAM read pointer to loop - inputchange_set_ram(block->start, block->body); + inputchange_set_ram(block->line_number, block->body); // parse block parse_until_eob_or_eof(); if (GotByte != CHAR_EOB) @@ -116,7 +116,7 @@ static void iterating_for(struct for_loop *loop) } -// back end function for "!for" pseudo opcode +// back end function for "!for" pseudo opcode, called with GotByte = '}' void flow_forloop(struct for_loop *loop) { struct inputchange_buf icb; @@ -124,7 +124,7 @@ void flow_forloop(struct for_loop *loop) // remember input and set up new one: inputchange_new_ram(&icb); // fix line number (not for block, but in case symbol handling throws errors) - inputchange_set_ram(loop->block.start, NULL); + inputchange_set_ram(loop->block.line_number, NULL); switch (loop->algorithm) { case FORALGO_OLDCOUNT: @@ -163,7 +163,7 @@ static void copy_condition(struct condition *condition, char terminator) GetByte(); } dynabuf_append(GlobalDynaBuf, CHAR_EOS); // ensure terminator - condition->body = dynabuf_get_copy(GlobalDynaBuf); + condition->block.body = dynabuf_get_copy(GlobalDynaBuf); } // try to read a condition into DynaBuf and store pointer to copy in @@ -173,10 +173,10 @@ static void copy_condition(struct condition *condition, char terminator) void flow_store_doloop_condition(struct condition *condition, char terminator) { // write line number - condition->line = input_now->location.line_number; + condition->block.line_number = input_now->location.line_number; // set defaults condition->invert = FALSE; - condition->body = NULL; + condition->block.body = NULL; // check for empty condition if (GotByte == terminator) return; @@ -202,7 +202,7 @@ void flow_store_doloop_condition(struct condition *condition, char terminator) // call with GotByte = first interesting character void flow_store_while_condition(struct condition *condition) { - condition->line = input_now->location.line_number; + condition->block.line_number = input_now->location.line_number; condition->invert = FALSE; copy_condition(condition, CHAR_SOB); } @@ -214,11 +214,11 @@ static boolean check_condition(struct condition *condition) struct number intresult; // first, check whether there actually *is* a condition - if (condition->body == NULL) + if (condition->block.body == NULL) return TRUE; // non-existing conditions are always true // set up input for expression evaluation - inputchange_set_ram(condition->line, condition->body); + inputchange_set_ram(condition->block.line_number, condition->block.body); // FIXME - just pass condition->block!) GetByte(); // proceed with next char ALU_defined_int(&intresult); @@ -247,11 +247,4 @@ void flow_do_while(struct do_while *loop) } // restore outer input inputchange_back(&icb); -// FIXME - the line above also restores GotByte, so this is no longer necessary, -// but check before removing: - GotByte = CHAR_EOS; // CAUTION! Very ugly kluge. - // But by switching input, we lost the outer input's GotByte. We know - // it was CHAR_EOS. We could just call GetByte() to get real input, but - // then the main loop could choke on unexpected bytes. So we pretend - // that we got the outer input's GotByte value magically back. } diff --git a/src/flow.h b/src/flow.h index e896088..9167a5c 100644 --- a/src/flow.h +++ b/src/flow.h @@ -11,11 +11,6 @@ #include "config.h" -struct block { - int start; // line number of start of block - char *body; -}; - // struct to pass "!for" loop stuff from pseudoopcodes.c to flow.c enum foralgo { FORALGO_OLDCOUNT, // block can be skipped by passing zero, counter keeps value after block @@ -42,9 +37,9 @@ struct for_loop { // structs to pass "!do"/"!while" stuff from pseudoopcodes.c to flow.c struct condition { - int line; // original line number - boolean invert; // only set for UNTIL conditions - char *body; // pointer to actual expression + // FIXME - add some "boolean given" and use that instead of checking for block.body == NULL + boolean invert; // only set for UNTIL conditions + struct block block; }; struct do_while { struct condition head_cond; diff --git a/src/global.c b/src/global.c index cd86a9d..0b08f57 100644 --- a/src/global.c +++ b/src/global.c @@ -436,7 +436,7 @@ int parse_optional_block(void) // "directory/basename.extension" on linux, // "directory.basename/extension" on RISC OS, etc. // and the pointer must remain valid forever! -void parse_and_close_platform_file(FILE *fd, const char *eternal_plat_filename) +void parse_source_code_file(FILE *fd, const char *eternal_plat_filename) { struct inputchange_buf icb; const char *ppb; // path buffer in platform format @@ -455,10 +455,6 @@ void parse_and_close_platform_file(FILE *fd, const char *eternal_plat_filename) parse_until_eob_or_eof(); if (GotByte != CHAR_EOF) Throw_error("Expected EOF, found '}' instead." ); - // close sublevel src - // (this looks like we could just use "fd" as arg, but maybe the file - // has been replaced with a different one in the meantime...) - fclose(input_now->src.fd); // restore outer input inputchange_back(&icb); @@ -498,21 +494,24 @@ bits parser_get_force_bit(void) static void throw_msg(const char *message, const char *ansicolor, const char *type) { const char *resetcolor = "\033[0m"; + struct location location; if (!config.format_color) { ansicolor = ""; resetcolor = ""; } + input_get_location(&location); + if (config.format_msvc) { fprintf(config.msg_stream, "%s(%d) : %s%s%s (%s %s): %s\n", - input_now->location.plat_filename, input_now->location.line_number, + location.plat_filename, location.line_number, ansicolor, type, resetcolor, section_now->type, section_now->title, message); } else { fprintf(config.msg_stream, "%s%s%s - File %s, line %d (%s %s): %s\n", ansicolor, type, resetcolor, - input_now->location.plat_filename, input_now->location.line_number, + location.plat_filename, location.line_number, section_now->type, section_now->title, message); } } @@ -579,8 +578,9 @@ void throw_redef_error(struct location *old_def, const char msg[]) // CAUTION, ugly kluge: fiddle with input_now and section_now // data so error message is actually helpful +// FIXME: maybe better pass "old location" as an optional arg to throw_message! // buffer old data - buffered_location = input_now->location; + input_get_location(&buffered_location); buffered_section_type = section_now->type; buffered_section_title = section_now->title; // set new (fake) data diff --git a/src/global.h b/src/global.h index 5c0e1e1..608cb3a 100644 --- a/src/global.h +++ b/src/global.h @@ -195,7 +195,7 @@ extern int parse_optional_block(void); // "directory/basename.extension" on linux, // "directory.basename/extension" on RISC OS, etc. // and the pointer must remain valid forever! -extern void parse_and_close_platform_file(FILE *fd, const char *eternal_plat_filename); +extern void parse_source_code_file(FILE *fd, const char *eternal_plat_filename); // read optional info about parameter length extern bits parser_get_force_bit(void); diff --git a/src/input.c b/src/input.c index 45501b1..2c6e538 100644 --- a/src/input.c +++ b/src/input.c @@ -512,19 +512,21 @@ void input_block_skip(void) { block_to_dynabuf(); } -// Read block into GlobalDynabuf, make a copy and return a pointer to that +// Read block into GlobalDynabuf, make a copy and store pointer in struct. // (reading starts with next byte, so call directly after reading opening brace). // After calling this function, GotByte holds '}'. Unless EOF was found first, // but then a serious error would have been thrown. -char *input_block_getcopy(void) +void input_block_getcopy(struct block *block) { + // first store line number... + block->line_number = input_now->location.line_number; + // ...then get block block_to_dynabuf(); - // prepare to return copy of block // add EOF, just to make sure block is never read too far dynabuf_append(GlobalDynaBuf, CHAR_EOS); dynabuf_append(GlobalDynaBuf, CHAR_EOF); - // return pointer to copy - return dynabuf_get_copy(GlobalDynaBuf); + // store pointer to copy + block->body = dynabuf_get_copy(GlobalDynaBuf); } // Append to GlobalDynaBuf while characters are legal for keywords. @@ -838,6 +840,12 @@ int input_read_output_filename(void) return 0; // ok } +// write current "location" (file name and line number) to given target +void input_get_location(struct location *target) +{ + *target = input_now->location; +} + // "input change" stuff: @@ -872,20 +880,20 @@ void inputchange_new_ram(struct inputchange_buf *icb) } // FIXME - merge these three functions into a single one (by always using a "location"): // setup for reading from RAM (for parsing loop conditions etc.) -void inputchange_set_ram(int line_num, char *body) +void inputchange_set_ram(int line_num, const char *body) { input_now->location.line_number = line_num; input_now->src.ram_ptr = body; } // switch input to macro parameters -void inputchange_macro1_params(struct location *def, char *params) +void inputchange_macro1_params(const struct location *def, const char *params) { input_now->location = *def; input_now->src.ram_ptr = params; input_now->state = INPUTSTATE_NORMAL; // FIXME - fix others! } // switch from macro parameters to macro body -void inputchange_macro2_body(char *macro_body) +void inputchange_macro2_body(const char *macro_body) { input_now->src.ram_ptr = macro_body; input_now->state = INPUTSTATE_NORMAL; // FIXME - fix others! diff --git a/src/input.h b/src/input.h index 4c4c73d..a53e9d9 100644 --- a/src/input.h +++ b/src/input.h @@ -25,7 +25,7 @@ struct input { int state; // state of input (type is really "enum inputstate") union { FILE *fd; // file descriptor - char *ram_ptr; // RAM read ptr (loop or macro block) + const char *ram_ptr; // RAM read ptr (loop or macro block) } src; }; struct filespecflags { @@ -80,11 +80,11 @@ extern int input_unescape_dynabuf(void); // After calling this function, GotByte holds '}'. Unless EOF was found first, // but then a serious error would have been thrown. extern void input_block_skip(void); -// Read block into GlobalDynabuf, make a copy and return a pointer to that +// Read block into GlobalDynabuf, make a copy and store pointer in struct. // (reading starts with next byte, so call directly after reading opening brace). // After calling this function, GotByte holds '}'. Unless EOF was found first, // but then a serious error would have been thrown. -extern char *input_block_getcopy(void); +extern void input_block_getcopy(struct block *block); // append optional '.'/'@' prefix to GlobalDynaBuf, then keep // appending while characters are legal for keywords. @@ -145,6 +145,9 @@ extern int input_expect(int chr); // (back end function for "!eof" pseudo opcode) extern void input_force_eof(void); +// write current "location" (file name and line number) to given target +extern void input_get_location(struct location *target); + // "input change" stuff: @@ -159,11 +162,11 @@ extern void inputchange_new_file(struct inputchange_buf *icb, FILE *fd, const ch // save current input struct in buffer, then switch to RAM extern void inputchange_new_ram(struct inputchange_buf *icb); // setup for reading from RAM (for parsing loop conditions etc.) -extern void inputchange_set_ram(int line_num, char *body); +extern void inputchange_set_ram(int line_num, const char *body); // switch input to macro parameters -extern void inputchange_macro1_params(struct location *def, char *params); +extern void inputchange_macro1_params(const struct location *def, const char *params); // switch from macro parameters to macro body -extern void inputchange_macro2_body(char *macro_body); +extern void inputchange_macro2_body(const char *macro_body); // restore input struct from buffer extern void inputchange_back(const struct inputchange_buf *icb); diff --git a/src/macro.c b/src/macro.c index 335f378..42fbbd7 100644 --- a/src/macro.c +++ b/src/macro.c @@ -29,8 +29,8 @@ struct macro { struct location definition; // for "macro twice" error char *original_name, // as section title in error msgs - *parameter_list, // parameters (whole line) - *body; // RAM block containing macro body + *parameter_list; // parameters (whole line) + struct block body; // RAM block containing macro body }; // there's no need to make this a struct and add a type component: // when the macro has been found, accessing its parameter_list component @@ -166,10 +166,10 @@ void macro_parse_definition(void) // Now GotByte = illegal char after "!macro" } // Create new macro struct and set it up. Finally we'll read the body. new_macro = safe_malloc(sizeof(*new_macro)); - new_macro->definition = input_now->location; new_macro->original_name = dynabuf_get_copy(user_macro_name); new_macro->parameter_list = formal_parameters; - new_macro->body = input_block_getcopy(); // changes line number! + input_get_location(&new_macro->definition); // includes line number + input_block_getcopy(&new_macro->body); // also includes line number (and then changes it) macro_node->body = new_macro; // link macro struct to tree node // and that about sums it up } @@ -287,7 +287,7 @@ void macro_parse_call(void) // Now GotByte = first char of macro name // and now, finally, parse the actual macro body // maybe call parse_ram_block(actual_macro->definition.line_number, actual_macro->body) - inputchange_macro2_body(actual_macro->body); + inputchange_macro2_body(actual_macro->body.body); parse_until_eob_or_eof(); if (GotByte != CHAR_EOB) BUG("IllegalBlockTerminator", GotByte); diff --git a/src/pseudoopcodes.c b/src/pseudoopcodes.c index 7d76834..b32c027 100644 --- a/src/pseudoopcodes.c +++ b/src/pseudoopcodes.c @@ -911,7 +911,8 @@ static enum eos po_source(void) // now GotByte = illegal char stream = includepaths_open_ro(&flags); if (stream) { eternal_plat_filename = dynabuf_get_copy(GlobalDynaBuf); - parse_and_close_platform_file(stream, eternal_plat_filename); + parse_source_code_file(stream, eternal_plat_filename); + fclose(stream); } // leave nesting level ++sanity.source_recursions_left; @@ -1141,16 +1142,11 @@ does not fail. */ if (GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); - // remember line number of loop pseudo opcode - loop.block.start = input_now->location.line_number; - // read loop body into DynaBuf and get copy - // reading block changes line number! - loop.block.body = input_block_getcopy(); // must be freed! + input_block_getcopy(&loop.block); // "body" must be freed afterward... flow_forloop(&loop); - // free memory - free(loop.block.body); + free(loop.block.body); // ...so free it - // GotByte of OuterInput would be '}' (if it would still exist) + // GotByte is '}' GetByte(); // fetch next byte return ENSURE_EOS; } @@ -1166,11 +1162,8 @@ static enum eos po_do(void) // now GotByte = illegal char flow_store_doloop_condition(&loop.head_cond, CHAR_SOB); // must be freed! if (GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); - // remember line number of loop body, - // then read block and get copy - loop.block.start = input_now->location.line_number; - // reading block changes line number! - loop.block.body = input_block_getcopy(); // must be freed! + + input_block_getcopy(&loop.block); // "body" must be freed! // now GotByte = '}' NEXTANDSKIPSPACE(); // now GotByte = first non-blank char after block // read tail condition to buffer @@ -1178,9 +1171,9 @@ static enum eos po_do(void) // now GotByte = illegal char // now GotByte = CHAR_EOS flow_do_while(&loop); // free memory - free(loop.head_cond.body); + free(loop.tail_cond.block.body); free(loop.block.body); - free(loop.tail_cond.body); + free(loop.head_cond.block.body); return AT_EOS_ANYWAY; } @@ -1192,22 +1185,18 @@ static enum eos po_while(void) // now GotByte = illegal char // read condition to buffer SKIPSPACE(); - flow_store_while_condition(&loop.head_cond); // must be freed! + flow_store_while_condition(&loop.head_cond); // "body" must be freed! if (GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); - // remember line number of loop body, - // then read block and get copy - loop.block.start = input_now->location.line_number; - // reading block changes line number! - loop.block.body = input_block_getcopy(); // must be freed! + // read block + input_block_getcopy(&loop.block); // "body" must be freed! // clear tail condition - loop.tail_cond.body = NULL; + loop.tail_cond.block.body = NULL; flow_do_while(&loop); // free memory - free(loop.head_cond.body); free(loop.block.body); - // GotByte of OuterInput would be '}' (if it would still exist) - GetByte(); // fetch next byte + free(loop.head_cond.block.body); + GetByte(); // fetch next byte (last byte read was '}') return ENSURE_EOS; } diff --git a/src/version.h b/src/version.h index f227f46..b46ad46 100644 --- a/src/version.h +++ b/src/version.h @@ -9,7 +9,7 @@ #define RELEASE "0.97" // update before release FIXME #define CODENAME "Zem" // update before release -#define CHANGE_DATE "23 Jul" // update before release FIXME +#define CHANGE_DATE "24 Jul" // update before release FIXME #define CHANGE_YEAR "2024" // update before release //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME