mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-11-24 13:17:29 +00:00
added "!break", "!continue" and "!return" (for loops and macros, respectively)
git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@447 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
45
src/flow.c
45
src/flow.c
@@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2024 Marco Baye
|
// Copyright (C) 1998-2025 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Flow control stuff (loops, conditional assembly etc.)
|
// Flow control stuff (loops, conditional assembly etc.)
|
||||||
@@ -67,6 +67,7 @@ static void parse_ram_block(struct block *block)
|
|||||||
static void counting_for(struct for_loop *loop)
|
static void counting_for(struct for_loop *loop)
|
||||||
{
|
{
|
||||||
struct object loop_var;
|
struct object loop_var;
|
||||||
|
enum shortcut shortcut;
|
||||||
|
|
||||||
// init counter
|
// init counter
|
||||||
loop_var.type = &type_number;
|
loop_var.type = &type_number;
|
||||||
@@ -95,6 +96,15 @@ static void counting_for(struct for_loop *loop)
|
|||||||
parse_ram_block(&loop->block);
|
parse_ram_block(&loop->block);
|
||||||
loop_var.u.number.val.intval += loop->u.counter.increment;
|
loop_var.u.number.val.intval += loop->u.counter.increment;
|
||||||
loop->iterations_left--;
|
loop->iterations_left--;
|
||||||
|
|
||||||
|
// was there a "!break" or "!continue"?
|
||||||
|
shortcut = parser_get_shortcut();
|
||||||
|
if (shortcut == SHORTCUT_BREAK) {
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
break;
|
||||||
|
} else if (shortcut == SHORTCUT_CONT) {
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// new algo wants illegal value in loop counter after block:
|
// new algo wants illegal value in loop counter after block:
|
||||||
if (loop->algorithm == FORALGO_NEWCOUNT)
|
if (loop->algorithm == FORALGO_NEWCOUNT)
|
||||||
@@ -106,12 +116,22 @@ static void iterating_for(struct for_loop *loop)
|
|||||||
{
|
{
|
||||||
intval_t index = 0;
|
intval_t index = 0;
|
||||||
struct object obj;
|
struct object obj;
|
||||||
|
enum shortcut shortcut;
|
||||||
|
|
||||||
while (loop->iterations_left) {
|
while (loop->iterations_left) {
|
||||||
loop->u.iter.obj.type->at(&loop->u.iter.obj, &obj, index++);
|
loop->u.iter.obj.type->at(&loop->u.iter.obj, &obj, index++);
|
||||||
symbol_set_object(loop->symbol, &obj, POWER_CHANGE_VALUE | POWER_CHANGE_OBJTYPE);
|
symbol_set_object(loop->symbol, &obj, POWER_CHANGE_VALUE | POWER_CHANGE_OBJTYPE);
|
||||||
parse_ram_block(&loop->block);
|
parse_ram_block(&loop->block);
|
||||||
loop->iterations_left--;
|
loop->iterations_left--;
|
||||||
|
|
||||||
|
// was there a "!break" or "!continue"?
|
||||||
|
shortcut = parser_get_shortcut();
|
||||||
|
if (shortcut == SHORTCUT_BREAK) {
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
break;
|
||||||
|
} else if (shortcut == SHORTCUT_CONT) {
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,11 +140,14 @@ static void iterating_for(struct for_loop *loop)
|
|||||||
void flow_forloop(struct for_loop *loop)
|
void flow_forloop(struct for_loop *loop)
|
||||||
{
|
{
|
||||||
struct inputchange_buf icb;
|
struct inputchange_buf icb;
|
||||||
|
boolean break_cont_buf;
|
||||||
|
|
||||||
// remember input and set up new one:
|
// remember input and set up new one:
|
||||||
inputchange_new_ram(&icb);
|
inputchange_new_ram(&icb);
|
||||||
// fix line number (not for block, but in case symbol handling throws errors)
|
// fix line number (not for block, but in case symbol handling throws errors)
|
||||||
inputchange_set_ram(loop->block.line_number, NULL);
|
inputchange_set_ram(loop->block.line_number, NULL);
|
||||||
|
// remember break/cont state and allow:
|
||||||
|
break_cont_buf = parser_allow_break_cont(TRUE);
|
||||||
|
|
||||||
switch (loop->algorithm) {
|
switch (loop->algorithm) {
|
||||||
case FORALGO_OLDCOUNT:
|
case FORALGO_OLDCOUNT:
|
||||||
@@ -138,6 +161,8 @@ void flow_forloop(struct for_loop *loop)
|
|||||||
BUG("IllegalLoopAlgo", loop->algorithm);
|
BUG("IllegalLoopAlgo", loop->algorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore outer break/cont state:
|
||||||
|
parser_allow_break_cont(break_cont_buf);
|
||||||
// restore outer input
|
// restore outer input
|
||||||
inputchange_back(&icb);
|
inputchange_back(&icb);
|
||||||
}
|
}
|
||||||
@@ -223,19 +248,37 @@ static boolean check_condition(struct condition *condition)
|
|||||||
void flow_do_while(struct do_while *loop)
|
void flow_do_while(struct do_while *loop)
|
||||||
{
|
{
|
||||||
struct inputchange_buf icb;
|
struct inputchange_buf icb;
|
||||||
|
boolean break_cont_buf;
|
||||||
|
enum shortcut shortcut;
|
||||||
|
|
||||||
// remember input and prepare new one:
|
// remember input and prepare new one:
|
||||||
inputchange_new_ram(&icb);
|
inputchange_new_ram(&icb);
|
||||||
|
// remember break/cont state and allow:
|
||||||
|
break_cont_buf = parser_allow_break_cont(TRUE);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// check head condition
|
// check head condition
|
||||||
if (!check_condition(&loop->head_cond))
|
if (!check_condition(&loop->head_cond))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
parse_ram_block(&loop->block);
|
parse_ram_block(&loop->block);
|
||||||
|
|
||||||
|
// was there a "!break" or "!continue"?
|
||||||
|
shortcut = parser_get_shortcut();
|
||||||
|
if (shortcut == SHORTCUT_BREAK) {
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
break;
|
||||||
|
} else if (shortcut == SHORTCUT_CONT) {
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
// check tail condition
|
// check tail condition
|
||||||
if (!check_condition(&loop->tail_cond))
|
if (!check_condition(&loop->tail_cond))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restore outer break/cont state:
|
||||||
|
parser_allow_break_cont(break_cont_buf);
|
||||||
// restore outer input
|
// restore outer input
|
||||||
inputchange_back(&icb);
|
inputchange_back(&icb);
|
||||||
}
|
}
|
||||||
|
|||||||
67
src/global.c
67
src/global.c
@@ -343,6 +343,33 @@ static void parse_forward_anon_def(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum shortcut current_shortcut_state = SHORTCUT_NONE;
|
||||||
|
// return current shortcut state
|
||||||
|
enum shortcut parser_get_shortcut(void)
|
||||||
|
{
|
||||||
|
return current_shortcut_state;
|
||||||
|
}
|
||||||
|
// start or end processing a !break/!continue/!return keyword
|
||||||
|
void parser_set_shortcut(enum shortcut new_shortcut)
|
||||||
|
{
|
||||||
|
//printf("Changing shortcut state from %d to %d.\n", current_shortcut_state, new_shortcut);
|
||||||
|
switch (new_shortcut) {
|
||||||
|
case SHORTCUT_NONE:
|
||||||
|
if (current_shortcut_state == SHORTCUT_NONE)
|
||||||
|
BUG("ShortcutDoubleNone", 0);
|
||||||
|
current_shortcut_state = new_shortcut;
|
||||||
|
break;
|
||||||
|
case SHORTCUT_BREAK:
|
||||||
|
case SHORTCUT_CONT:
|
||||||
|
case SHORTCUT_RETURN:
|
||||||
|
if (current_shortcut_state != SHORTCUT_NONE)
|
||||||
|
BUG("ShortcutDouble", current_shortcut_state);
|
||||||
|
current_shortcut_state = new_shortcut;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG("IllegalShortcut", new_shortcut);
|
||||||
|
}
|
||||||
|
}
|
||||||
// status var to tell mainloop (actually "statement loop") to exit.
|
// status var to tell mainloop (actually "statement loop") to exit.
|
||||||
// this is better than the error handler exiting directly, because
|
// this is better than the error handler exiting directly, because
|
||||||
// there are cases where an error message is followed by an info message
|
// there are cases where an error message is followed by an info message
|
||||||
@@ -417,8 +444,14 @@ void parse_until_eob_or_eof(void)
|
|||||||
// did the error handler decide to give up?
|
// did the error handler decide to give up?
|
||||||
if (too_many_errors)
|
if (too_many_errors)
|
||||||
exit(ACME_finalize(EXIT_FAILURE));
|
exit(ACME_finalize(EXIT_FAILURE));
|
||||||
// go on with next byte
|
// was any of the shortcut POs used?
|
||||||
GetByte(); //NEXTANDSKIPSPACE();
|
if (current_shortcut_state == SHORTCUT_NONE) {
|
||||||
|
// go on with next byte
|
||||||
|
GetByte(); //NEXTANDSKIPSPACE();
|
||||||
|
} else {
|
||||||
|
// ignore remainder of block:
|
||||||
|
input_block_skip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,6 +481,8 @@ void parse_source_code_file(FILE *fd, const char *eternal_plat_filename)
|
|||||||
{
|
{
|
||||||
struct inputchange_buf icb;
|
struct inputchange_buf icb;
|
||||||
const char *ppb; // path buffer in platform format
|
const char *ppb; // path buffer in platform format
|
||||||
|
boolean break_cont_allowed;
|
||||||
|
boolean return_allowed;
|
||||||
|
|
||||||
// be verbose
|
// be verbose
|
||||||
if (config.process_verbosity >= 3)
|
if (config.process_verbosity >= 3)
|
||||||
@@ -458,12 +493,19 @@ void parse_source_code_file(FILE *fd, const char *eternal_plat_filename)
|
|||||||
input_plat_pathref_filename = eternal_plat_filename;
|
input_plat_pathref_filename = eternal_plat_filename;
|
||||||
// remember input and set up new one:
|
// remember input and set up new one:
|
||||||
inputchange_new_file(&icb, fd, eternal_plat_filename);
|
inputchange_new_file(&icb, fd, eternal_plat_filename);
|
||||||
|
// remember whether break/continue/return are allowed and forbid them in
|
||||||
|
// new file (just to enforce "clean code"):
|
||||||
|
break_cont_allowed = parser_allow_break_cont(FALSE);
|
||||||
|
return_allowed = parser_allow_return(FALSE);
|
||||||
|
|
||||||
// parse block and check end reason
|
// parse block and check end reason
|
||||||
parse_until_eob_or_eof();
|
parse_until_eob_or_eof();
|
||||||
if (GotByte != CHAR_EOF)
|
if (GotByte != CHAR_EOF)
|
||||||
throw_error("Expected EOF, found '}' instead." );
|
throw_error("Expected EOF, found '}' instead." );
|
||||||
|
|
||||||
|
// restore states of break/continue/return
|
||||||
|
parser_allow_return(return_allowed);
|
||||||
|
parser_allow_break_cont(break_cont_allowed);
|
||||||
// restore outer input
|
// restore outer input
|
||||||
inputchange_back(&icb);
|
inputchange_back(&icb);
|
||||||
// restore outer base for relative paths
|
// restore outer base for relative paths
|
||||||
@@ -493,6 +535,27 @@ bits parser_get_force_bit(void)
|
|||||||
return force_bit;
|
return force_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return current state and set new state of "allow !break and !continue" flag
|
||||||
|
boolean parser_allow_break_cont(boolean new_state)
|
||||||
|
{
|
||||||
|
static boolean flag = FALSE;
|
||||||
|
boolean temp;
|
||||||
|
|
||||||
|
temp = flag;
|
||||||
|
flag = new_state;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
// return current state and set new state of "allow !return" flag
|
||||||
|
boolean parser_allow_return(boolean new_state)
|
||||||
|
{
|
||||||
|
static boolean flag = FALSE;
|
||||||
|
boolean temp;
|
||||||
|
|
||||||
|
temp = flag;
|
||||||
|
flag = new_state;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Error handling
|
// Error handling
|
||||||
|
|
||||||
|
|||||||
18
src/global.h
18
src/global.h
@@ -106,6 +106,12 @@ struct config {
|
|||||||
};
|
};
|
||||||
extern struct config config;
|
extern struct config config;
|
||||||
|
|
||||||
|
enum shortcut {
|
||||||
|
SHORTCUT_NONE, // normal execution
|
||||||
|
SHORTCUT_BREAK, // after "!break"
|
||||||
|
SHORTCUT_CONT, // after "!continue"
|
||||||
|
SHORTCUT_RETURN // after "!return"
|
||||||
|
};
|
||||||
struct pass {
|
struct pass {
|
||||||
int number; // counts up from one
|
int number; // counts up from one
|
||||||
struct {
|
struct {
|
||||||
@@ -215,6 +221,18 @@ extern void parse_source_code_file(FILE *fd, const char *eternal_plat_filename);
|
|||||||
// read optional info about parameter length
|
// read optional info about parameter length
|
||||||
extern bits parser_get_force_bit(void);
|
extern bits parser_get_force_bit(void);
|
||||||
|
|
||||||
|
// return current shortcut state
|
||||||
|
extern enum shortcut parser_get_shortcut(void);
|
||||||
|
|
||||||
|
// start or end processing a !break/!continue/!return keyword
|
||||||
|
extern void parser_set_shortcut(enum shortcut);
|
||||||
|
|
||||||
|
// return current state and set new state of "allow !break and !continue" flag
|
||||||
|
extern boolean parser_allow_break_cont(boolean new_state);
|
||||||
|
|
||||||
|
// return current state and set new state of "allow !return" flag
|
||||||
|
extern boolean parser_allow_return(boolean new_state);
|
||||||
|
|
||||||
// generate a debug/info/warning/error message
|
// generate a debug/info/warning/error message
|
||||||
// if the "optional alternative location" given is NULL, the current location is used
|
// if the "optional alternative location" given is NULL, the current location is used
|
||||||
extern void throw_message(enum debuglevel level, const char msg[], struct location *opt_alt_loc);
|
extern void throw_message(enum debuglevel level, const char msg[], struct location *opt_alt_loc);
|
||||||
|
|||||||
16
src/macro.c
16
src/macro.c
@@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2024 Marco Baye
|
// Copyright (C) 1998-2025 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Macro stuff
|
// Macro stuff
|
||||||
@@ -189,6 +189,8 @@ void macro_parse_call(void) // Now GotByte = first char of macro name
|
|||||||
symbol_scope;
|
symbol_scope;
|
||||||
int arg_count = 0;
|
int arg_count = 0;
|
||||||
int outer_msg_sum;
|
int outer_msg_sum;
|
||||||
|
boolean break_cont_allowed;
|
||||||
|
boolean return_allowed;
|
||||||
|
|
||||||
// make sure arg_table is ready (if not yet initialised, do it now)
|
// make sure arg_table is ready (if not yet initialised, do it now)
|
||||||
if (arg_table == NULL)
|
if (arg_table == NULL)
|
||||||
@@ -285,12 +287,24 @@ void macro_parse_call(void) // Now GotByte = first char of macro name
|
|||||||
} while (parser_accept_comma());
|
} while (parser_accept_comma());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remember whether break/continue/return are allowed and set new states
|
||||||
|
break_cont_allowed = parser_allow_break_cont(FALSE); // forbid !break/!continue
|
||||||
|
return_allowed = parser_allow_return(TRUE); // allow !return
|
||||||
|
|
||||||
// and now, finally, parse the actual macro body
|
// and now, finally, parse the actual macro body
|
||||||
// maybe call parse_ram_block(actual_macro->definition.line_number, actual_macro->body)
|
// maybe call parse_ram_block(actual_macro->definition.line_number, actual_macro->body)
|
||||||
inputchange_macro2_body(actual_macro->body.body);
|
inputchange_macro2_body(actual_macro->body.body);
|
||||||
parse_until_eob_or_eof();
|
parse_until_eob_or_eof();
|
||||||
if (GotByte != CHAR_EOB)
|
if (GotByte != CHAR_EOB)
|
||||||
BUG("IllegalBlockTerminator", GotByte);
|
BUG("IllegalBlockTerminator", GotByte);
|
||||||
|
// was there a "!return"?
|
||||||
|
if (parser_get_shortcut() == SHORTCUT_RETURN)
|
||||||
|
parser_set_shortcut(SHORTCUT_NONE);
|
||||||
|
|
||||||
|
// restore states of break/continue/return
|
||||||
|
parser_allow_return(return_allowed);
|
||||||
|
parser_allow_break_cont(break_cont_allowed);
|
||||||
|
|
||||||
// end section (free title memory, if needed)
|
// end section (free title memory, if needed)
|
||||||
section_finalize(&new_section);
|
section_finalize(&new_section);
|
||||||
// restore previous section
|
// restore previous section
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2024 Marco Baye
|
// Copyright (C) 1998-2025 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// pseudo opcode stuff
|
// pseudo opcode stuff
|
||||||
@@ -28,6 +28,10 @@
|
|||||||
static boolean line_uses_keyword_arguments(void)
|
static boolean line_uses_keyword_arguments(void)
|
||||||
{
|
{
|
||||||
// to be on the safe side, return FALSE if dialect < 0.98!
|
// to be on the safe side, return FALSE if dialect < 0.98!
|
||||||
|
// if (config.dialect < V0_98__PATHS_AND_SYMBOLCHANGE)
|
||||||
|
// return FALSE;
|
||||||
|
//
|
||||||
|
//
|
||||||
// read line to buffer, check if it begins with '[a-zA-Z]+='
|
// read line to buffer, check if it begins with '[a-zA-Z]+='
|
||||||
// change input to RAM, return result
|
// change input to RAM, return result
|
||||||
// ...and the caller needs to pass us some struct so it can change input back later on!
|
// ...and the caller needs to pass us some struct so it can change input back later on!
|
||||||
@@ -943,15 +947,14 @@ static enum eos po_source(void) // now GotByte = illegal char
|
|||||||
FILE *stream;
|
FILE *stream;
|
||||||
const char *eternal_plat_filename;
|
const char *eternal_plat_filename;
|
||||||
|
|
||||||
// enter new nesting level
|
|
||||||
// quit program if recursion too deep
|
|
||||||
if (--sanity.source_recursions_left < 0)
|
|
||||||
throw_serious_error("Too deeply nested. Recursive \"!source\"?");
|
|
||||||
|
|
||||||
// read file name and convert from UNIX style to platform style
|
// read file name and convert from UNIX style to platform style
|
||||||
if (input_read_input_filename(&flags))
|
if (input_read_input_filename(&flags))
|
||||||
return SKIP_REMAINDER; // if missing or unterminated, give up
|
return SKIP_REMAINDER; // if missing or unterminated, give up
|
||||||
|
|
||||||
|
// enter new nesting level
|
||||||
|
// quit program if recursion too deep
|
||||||
|
if (--sanity.source_recursions_left < 0)
|
||||||
|
throw_serious_error("Too deeply nested. Recursive \"!source\"?");
|
||||||
// if file could be opened, parse it. otherwise, complain
|
// if file could be opened, parse it. otherwise, complain
|
||||||
stream = includepaths_open_ro(&flags);
|
stream = includepaths_open_ro(&flags);
|
||||||
if (stream) {
|
if (stream) {
|
||||||
@@ -1378,6 +1381,52 @@ static enum eos po_nowarn(void) // now GotByte = illegal char
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// exit innermost loop
|
||||||
|
static enum eos po_break(void) // now GotByte = illegal char
|
||||||
|
{
|
||||||
|
boolean allowed;
|
||||||
|
|
||||||
|
allowed = parser_allow_break_cont(FALSE);
|
||||||
|
parser_allow_break_cont(allowed);
|
||||||
|
if (allowed)
|
||||||
|
parser_set_shortcut(SHORTCUT_BREAK);
|
||||||
|
else
|
||||||
|
throw_error("!break not within a loop.");
|
||||||
|
return ENSURE_EOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// end innermost loop iteration
|
||||||
|
static enum eos po_continue(void) // now GotByte = illegal char
|
||||||
|
{
|
||||||
|
boolean allowed;
|
||||||
|
|
||||||
|
allowed = parser_allow_break_cont(FALSE);
|
||||||
|
parser_allow_break_cont(allowed);
|
||||||
|
if (allowed)
|
||||||
|
parser_set_shortcut(SHORTCUT_CONT);
|
||||||
|
else
|
||||||
|
throw_error("!continue not within a loop.");
|
||||||
|
return ENSURE_EOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return from innermost macro
|
||||||
|
static enum eos po_return(void) // now GotByte = illegal char
|
||||||
|
{
|
||||||
|
boolean allowed;
|
||||||
|
|
||||||
|
// if ACME ever gets real functions, this is the place to parse the
|
||||||
|
// return value and store it via some innermost_function->result
|
||||||
|
// pointer.
|
||||||
|
allowed = parser_allow_return(FALSE);
|
||||||
|
parser_allow_return(allowed);
|
||||||
|
if (allowed)
|
||||||
|
parser_set_shortcut(SHORTCUT_RETURN);
|
||||||
|
else
|
||||||
|
throw_error("!return not within a macro.");
|
||||||
|
return ENSURE_EOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
static STRUCT_DYNABUF_REF(user_message, 80); // for !debug/info/warn/error/serious
|
static STRUCT_DYNABUF_REF(user_message, 80); // for !debug/info/warn/error/serious
|
||||||
|
|
||||||
@@ -1542,6 +1591,9 @@ static struct ronode pseudo_opcode_tree[] = {
|
|||||||
PREDEFNODE("addr", po_address),
|
PREDEFNODE("addr", po_address),
|
||||||
PREDEFNODE("address", po_address),
|
PREDEFNODE("address", po_address),
|
||||||
PREDEFNODE("nowarn", po_nowarn),
|
PREDEFNODE("nowarn", po_nowarn),
|
||||||
|
PREDEFNODE("break", po_break),
|
||||||
|
PREDEFNODE("continue", po_continue),
|
||||||
|
PREDEFNODE("return", po_return),
|
||||||
PREDEFNODE("debug", po_debug),
|
PREDEFNODE("debug", po_debug),
|
||||||
PREDEFNODE("info", po_info),
|
PREDEFNODE("info", po_info),
|
||||||
PREDEFNODE("warn", po_warn),
|
PREDEFNODE("warn", po_warn),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#define RELEASE "0.97" // update before release FIXME
|
#define RELEASE "0.97" // update before release FIXME
|
||||||
#define CODENAME "Zem" // update before release
|
#define CODENAME "Zem" // update before release
|
||||||
#define CHANGE_DATE "11 Jul" // update before release FIXME
|
#define CHANGE_DATE "26 Jul" // update before release FIXME
|
||||||
#define CHANGE_YEAR "2025" // update before release
|
#define CHANGE_YEAR "2025" // update before release
|
||||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||||
|
|||||||
26
testing/auto/breakcontinuereturn.a
Normal file
26
testing/auto/breakcontinuereturn.a
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
!for @n in [2, 3] {
|
||||||
|
!if @n == 3 {
|
||||||
|
!error "!break does not leave the loop"
|
||||||
|
}
|
||||||
|
!if 1 {
|
||||||
|
!break
|
||||||
|
}
|
||||||
|
!error "!break is ignored"
|
||||||
|
}
|
||||||
|
!for @n in [2, 3] {
|
||||||
|
!if 1 {
|
||||||
|
!continue
|
||||||
|
}
|
||||||
|
!error "!continue does not skip the remainder of the block"
|
||||||
|
}
|
||||||
|
!macro testmacro {
|
||||||
|
!for @n in [2, 3] {
|
||||||
|
!if 1 {
|
||||||
|
!return
|
||||||
|
}
|
||||||
|
!error "!return does not leave the block"
|
||||||
|
}
|
||||||
|
!error "!return does not leave all blocks"
|
||||||
|
}
|
||||||
|
+testmacro
|
||||||
4
testing/errors/breaknotwithinaloop1.a
Normal file
4
testing/errors/breaknotwithinaloop1.a
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
; (this file also gets included by breaknotwithinaloop2.a)
|
||||||
|
|
||||||
|
; "!break" only works inside a loop:
|
||||||
|
!break ; -> "!break not within a loop"
|
||||||
5
testing/errors/breaknotwithinaloop2.a
Normal file
5
testing/errors/breaknotwithinaloop2.a
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
; "!break" in a file is not supposed to break from a loop outside the file:
|
||||||
|
!for @i in "ab" {
|
||||||
|
!src "breaknotwithinaloop1.a" ; -> "!break not within a loop"
|
||||||
|
}
|
||||||
9
testing/errors/breaknotwithinaloop3.a
Normal file
9
testing/errors/breaknotwithinaloop3.a
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
; "!break" inside a macro is not supposed to break from a loop outside the macro:
|
||||||
|
!macro testmacro {
|
||||||
|
!break ; -> "!break not within a loop"
|
||||||
|
}
|
||||||
|
|
||||||
|
!for @i, 0, 2 {
|
||||||
|
+testmacro
|
||||||
|
}
|
||||||
4
testing/errors/continuenotwithinaloop1.a
Normal file
4
testing/errors/continuenotwithinaloop1.a
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
; (this file also gets included by continuenotwithinaloop2.a)
|
||||||
|
|
||||||
|
; "!continue" only works inside a loop:
|
||||||
|
!continue ; -> "!continue not within a loop"
|
||||||
5
testing/errors/continuenotwithinaloop2.a
Normal file
5
testing/errors/continuenotwithinaloop2.a
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
; "!continue" in a file is not supposed to continue a loop outside the file:
|
||||||
|
!do {
|
||||||
|
!src "continuenotwithinaloop1.a" ; -> "!continue not within a loop"
|
||||||
|
} while 0
|
||||||
10
testing/errors/continuenotwithinaloop3.a
Normal file
10
testing/errors/continuenotwithinaloop3.a
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
; "!continue" inside a macro is not supposed to continue a loop outside the macro:
|
||||||
|
!macro testmacro {
|
||||||
|
!continue ; -> "!continue not within a loop"
|
||||||
|
}
|
||||||
|
|
||||||
|
!while 1 {
|
||||||
|
+testmacro
|
||||||
|
!break ; inhibit infinite loop :)
|
||||||
|
}
|
||||||
4
testing/errors/returnnotwithinamacro1.a
Normal file
4
testing/errors/returnnotwithinamacro1.a
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
; (this file also gets included by returnnotwithinamacro2.a)
|
||||||
|
|
||||||
|
; "!return" only works inside a macro:
|
||||||
|
!return ; -> "!return not within a macro"
|
||||||
7
testing/errors/returnnotwithinamacro2.a
Normal file
7
testing/errors/returnnotwithinamacro2.a
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
; "!return" in a file is not supposed to return from a macro outside the file:
|
||||||
|
!macro testmacro {
|
||||||
|
!src "returnnotwithinamacro1.a" ; -> "!return not within a macro"
|
||||||
|
}
|
||||||
|
|
||||||
|
+testmacro
|
||||||
Reference in New Issue
Block a user