interp/call_fsm wip

oword sub, python oword sub runtests ok
remap TBD
This commit is contained in:
Michael Haberler 2011-09-11 22:39:34 +02:00
parent 5e71ed5ef6
commit de556674f3
2 changed files with 252 additions and 80 deletions

View file

@ -142,9 +142,7 @@ enum SPINDLE_MODE { CONSTANT_RPM, CONSTANT_SURFACE };
#define O_return 13 #define O_return 13
#define O_repeat 14 #define O_repeat 14
#define O_endrepeat 15 #define O_endrepeat 15
#define O_remap 16 // not a keyword - just indicates a remap call in progress #define O_continue_call 16 // signal Python handler reexecution
#define O_pycall 17 // like O_call, but o_name is a Python callable
#define O_continue_call 18 // signal Python handler reexecution
// G Codes are symbolic to be dialect-independent in source code // G Codes are symbolic to be dialect-independent in source code
#define G_0 0 #define G_0 0
@ -473,18 +471,20 @@ typedef struct block_struct
int phase; // current remap execution phase int phase; // current remap execution phase
} }
block; block;
enum call_states { enum call_states {
CS_START, CS_START,
CS_CALL_PROLOG, CS_CALL_PROLOG,
CS_CONTINUE_PROLOG, CS_CONTINUE_PROLOG,
CS_CALL_BODY, CS_CALL_BODY,
CS_CONTINUE_BODY, CS_EXECUTING_BODY,
CS_CALL_EPILOG, CS_CALL_EPILOG,
CS_CONTINUE_EPILOG, CS_CONTINUE_EPILOG,
CS_CALL_PYBODY, CS_CALL_PYBODY,
CS_CONTINUE_PYBODY, CS_CONTINUE_PYBODY,
CS_CALL_PY_OSUB, CS_CALL_PY_OSUB,
CS_CONTINUE_PY_OSUB, CS_CONTINUE_PY_OSUB,
CS_CALL_REMAP,
CS_DONE CS_DONE
}; };

View file

@ -85,30 +85,29 @@ int Interp::findFile( // ARGUMENTS
int Interp::control_save_offset(block_pointer block, /* pointer to a block of RS274/NGC instructions */ int Interp::control_save_offset(block_pointer block, /* pointer to a block of RS274/NGC instructions */
setup_pointer settings) /* pointer to machine settings */ setup_pointer settings) /* pointer to machine settings */
{ {
static char name[] = "control_save_offset"; static char name[] = "control_save_offset";
offset_pointer op = NULL; offset_pointer op = NULL;
logOword("Entered:%s for o_name:|%s|", name, block->o_name); logOword("Entered:%s for o_name:|%s|", name, block->o_name);
if (control_find_oword(block, settings, &op) == INTERP_OK) { if (control_find_oword(block, settings, &op) == INTERP_OK) {
// already exists // already exists
ERS(_("File:%s line:%d redefining sub: o|%s| already defined in file:%s"), ERS(_("File:%s line:%d redefining sub: o|%s| already defined in file:%s"),
settings->filename, settings->sequence_number, settings->filename, settings->sequence_number,
block->o_name, block->o_name,
op->filename); op->filename);
} }
offset new_offset; offset new_offset;
new_offset.type = block->o_type; new_offset.type = block->o_type;
new_offset.offset = block->offset; new_offset.offset = block->offset;
new_offset.filename = strstore(settings->filename); new_offset.filename = strstore(settings->filename);
new_offset.repeat_count = -1; new_offset.repeat_count = -1;
// the sequence number has already been bumped, so save // the sequence number has already been bumped, so save
// the proper value // the proper value
new_offset.sequence_number = settings->sequence_number - 1; new_offset.sequence_number = settings->sequence_number - 1;
settings->offset_map[block->o_name] = new_offset; settings->offset_map[block->o_name] = new_offset;
return INTERP_OK;
return INTERP_OK;
} }
@ -382,7 +381,7 @@ int Interp::execute_call(setup_pointer settings, int what)
} // end case } // end case
return status; return status;
} }
#endif
int Interp::execute_return(setup_pointer settings, int what) // pointer to machine settings int Interp::execute_return(setup_pointer settings, int what) // pointer to machine settings
{ {
@ -419,37 +418,37 @@ int Interp::execute_return(setup_pointer settings, int what) // pointer to mac
// we call the epilog handler while the current frame is still alive // we call the epilog handler while the current frame is still alive
// so we can inspect it from the epilog // so we can inspect it from the epilog
if (HAS_PYTHON_EPILOG(cblock->executing_remap)) { // if (HAS_PYTHON_EPILOG(cblock->executing_remap)) {
// FIXME not necessarily an NGC remap! // // FIXME not necessarily an NGC remap!
logRemap("O_endsub/return: epilog %s for NGC remap %s cl=%d rl=%d", // logRemap("O_endsub/return: epilog %s for NGC remap %s cl=%d rl=%d",
cblock->executing_remap->epilog_func, // cblock->executing_remap->epilog_func,
cblock->executing_remap->remap_ngc,settings->call_level, // cblock->executing_remap->remap_ngc,settings->call_level,
settings->remap_level); // settings->remap_level);
status = pycall(settings,leaving_frame, // status = pycall(settings,leaving_frame,
REMAP_MODULE, // REMAP_MODULE,
cblock->executing_remap->epilog_func, // cblock->executing_remap->epilog_func,
PY_EPILOG); // PY_EPILOG);
if (status > INTERP_MIN_ERROR) { // if (status > INTERP_MIN_ERROR) {
logRemap("O_endsub/return: epilog %s failed, unwinding", // logRemap("O_endsub/return: epilog %s failed, unwinding",
cblock->executing_remap->epilog_func); // cblock->executing_remap->epilog_func);
ERP(status); // ERP(status);
} // }
if (status == INTERP_EXECUTE_FINISH) { // if (status == INTERP_EXECUTE_FINISH) {
leaving_frame->call_phase = FINISH_EPILOG; // leaving_frame->call_phase = FINISH_EPILOG;
logRemap("O_endsub/return: epilog %s INTERP_EXECUTE_FINISH, mark for restart, cl=%d rl=%d", // logRemap("O_endsub/return: epilog %s INTERP_EXECUTE_FINISH, mark for restart, cl=%d rl=%d",
cblock->executing_remap->epilog_func, // cblock->executing_remap->epilog_func,
settings->call_level,settings->remap_level); // settings->call_level,settings->remap_level);
return INTERP_EXECUTE_FINISH; // return INTERP_EXECUTE_FINISH;
} // }
if (status == INTERP_OK) { // if (status == INTERP_OK) {
if (leaving_frame->call_phase == FINISH_EPILOG) { // if (leaving_frame->call_phase == FINISH_EPILOG) {
leaving_frame->call_phase = NONE; // leaving_frame->call_phase = NONE;
logRemap("O_call: epilog %s done after restart cl=%d rl=%d", // logRemap("O_call: epilog %s done after restart cl=%d rl=%d",
cblock->executing_remap->epilog_func, // cblock->executing_remap->epilog_func,
settings->call_level,settings->remap_level); // settings->call_level,settings->remap_level);
} // }
} // }
} // }
// free local variables // free local variables
free_named_parameters(leaving_frame); free_named_parameters(leaving_frame);
@ -508,7 +507,7 @@ int Interp::execute_return(setup_pointer settings, int what) // pointer to mac
} else { } else {
settings->sub_name = NULL; settings->sub_name = NULL;
} }
} else { } else { // call_level == 0
// a definition // a definition
if (eblock->o_type == O_endsub) { if (eblock->o_type == O_endsub) {
CHKS((settings->defining_sub != 1), NCE_NOT_IN_SUBROUTINE_DEFN); CHKS((settings->defining_sub != 1), NCE_NOT_IN_SUBROUTINE_DEFN);
@ -525,7 +524,6 @@ int Interp::execute_return(setup_pointer settings, int what) // pointer to mac
} // end case } // end case
return status; return status;
} }
#endif
// //
// TESTME!!! MORE THOROUGHLY !!!KL // TESTME!!! MORE THOROUGHLY !!!KL
@ -625,8 +623,6 @@ static const char *o_ops[] = {
"O_return", "O_return",
"O_repeat", "O_repeat",
"O_endrepeat", "O_endrepeat",
"O_remap",
"O_pycall",
"O_continue_call", "O_continue_call",
}; };
static const char *call_phases[] = { static const char *call_phases[] = {
@ -634,13 +630,14 @@ static const char *call_phases[] = {
"CS_CALL_PROLOG", "CS_CALL_PROLOG",
"CS_CONTINUE_PROLOG", "CS_CONTINUE_PROLOG",
"CS_CALL_BODY", "CS_CALL_BODY",
"CS_CONTINUE_BODY", "CS_EXECUTING_BODY",
"CS_CALL_EPILOG", "CS_CALL_EPILOG",
"CS_CONTINUE_EPILOG", "CS_CONTINUE_EPILOG",
"CS_CALL_PYBODY", "CS_CALL_PYBODY",
"CS_CONTINUE_PYBODY", "CS_CONTINUE_PYBODY",
"CS_CALL_PY_OSUB", "CS_CALL_PY_OSUB",
"CS_CONTINUE_PY_OSUB" "CS_CONTINUE_PY_OSUB",
"CS_CALL_REMAP",
"CS_DONE" "CS_DONE"
}; };
// Propagate an error up the stack as with ERP if the result of 'call' is not // Propagate an error up the stack as with ERP if the result of 'call' is not
@ -653,6 +650,9 @@ static const char *call_phases[] = {
} \ } \
} while(0) } while(0)
#define INVALID_EVENT(cond) CHKS(cond,"call_fsm: invalid event=%s in state=%s cl=%d rl=%d", \
o_ops[event], call_phases[active_frame->state], \
settings->call_level, settings->remap_level);
// call handling FSM. // call handling FSM.
// when called, call frame is already established // when called, call frame is already established
@ -667,14 +667,14 @@ int Interp::call_fsm(setup_pointer settings, int event)
bp::list plist; bp::list plist;
do { do {
logOword("call_fsm event=%s state=%s cl=%d rl=%d", logOword("call_fsm: event=%s state=%s cl=%d rl=%d status=%s",
o_ops[event], call_phases[active_frame->state], o_ops[event], call_phases[active_frame->state],
settings->call_level, settings->remap_level); settings->call_level, settings->remap_level, interp_status(status));
switch (active_frame->state) { switch (active_frame->state) {
case CS_CALL_PY_OSUB: // first time around case CS_CALL_PY_OSUB: // first time around
CHKS(event != O_pycall,"baaad.."); INVALID_EVENT(event != O_call);
settings->return_value = 0.0; settings->return_value = 0.0;
settings->value_returned = 0; settings->value_returned = 0;
plist.append(settings->pythis); // self plist.append(settings->pythis); // self
@ -699,7 +699,7 @@ int Interp::call_fsm(setup_pointer settings, int event)
break; break;
case CS_CONTINUE_PY_OSUB: // continuation post synch() case CS_CONTINUE_PY_OSUB: // continuation post synch()
CHKS(event != O_continue_call,"baaad.."); INVALID_EVENT(event != O_continue_call);
CHP(read_inputs(settings)); // update toolchange/input/probe data CHP(read_inputs(settings)); // update toolchange/input/probe data
CHP(pycall(settings, active_frame, OWORD_MODULE, CHP(pycall(settings, active_frame, OWORD_MODULE,
active_frame->subName, PY_FINISH_OWORDCALL)); active_frame->subName, PY_FINISH_OWORDCALL));
@ -714,13 +714,185 @@ int Interp::call_fsm(setup_pointer settings, int event)
} }
break; break;
case CS_CALL_BODY: // NGC oword procedure
INVALID_EVENT(event != O_call);
// copy parameters from context
// save old values of parameters
// save current file position in context
// if we were skipping, no longer
if (settings->skipping_o) {
logOword("case O_call -- no longer skipping to:|%s|",
settings->skipping_o);
settings->skipping_o = NULL;
}
for(int i = 0; i < INTERP_SUB_PARAMS; i++) {
previous_frame->saved_params[i] =
settings->parameters[i + INTERP_FIRST_SUBROUTINE_PARAM];
settings->parameters[i + INTERP_FIRST_SUBROUTINE_PARAM] =
eblock->params[i];
}
// if the previous file was NULL, mark positon as -1 so as not to
// reopen it on return.
if (settings->file_pointer == NULL) {
previous_frame->position = -1;
} else {
previous_frame->position = ftell(settings->file_pointer);
}
// save return location
previous_frame->filename = strstore(settings->filename);
previous_frame->sequence_number = settings->sequence_number;
logOword("return location: %s:%d offset=%ld cl=%d",
previous_frame->filename,
previous_frame->sequence_number,
previous_frame->position,
settings->call_level);
// set the new subName
active_frame->subName = eblock->o_name;
// let any Oword sub know the number of parameters
CHP(add_named_param("n_args", PA_READONLY));
CHP(store_named_param(settings, "n_args",
(double )eblock->param_cnt,
OVERRIDE_READONLY));
if (control_back_to(eblock, settings) == INTERP_ERROR) {
settings->call_level--; //FIXTHIS - leave_context
ERS(NCE_UNABLE_TO_OPEN_FILE,eblock->o_name);
status = INTERP_ERROR;
}
active_frame->state = CS_EXECUTING_BODY;
break;
case CS_EXECUTING_BODY: // NGC oword procedure
INVALID_EVENT((event != O_return) && (event != O_endsub));
if (settings->skipping_o) {
logOword("case O_%s -- no longer skipping to:|%s|",
(eblock->o_type == O_endsub) ? "endsub" : "return",
settings->skipping_o);
settings->skipping_o = NULL;
}
if (settings->call_level != 0) {
int context_status = active_frame->context_status; // leave_context wipes this
CHP(leave_context(settings, false));
// free_named_parameters(active_frame); // free local variables
// leaving_frame->subName = NULL;
// drop one call level.
// settings->call_level--;
// restore subroutine parameters.
for(int i = 0; i < INTERP_SUB_PARAMS; i++) {
settings->parameters[i+INTERP_FIRST_SUBROUTINE_PARAM] =
previous_frame->saved_params[i];
}
// file at this level was marked as closed, so dont reopen.
if (previous_frame->position == -1) {
settings->file_pointer = NULL;
strcpy(settings->filename, "");
} else {
logOword("seeking to: %ld", previous_frame->position);
if(settings->file_pointer == NULL) {
ERS(NCE_FILE_NOT_OPEN);
}
//!!!KL must open the new file, if changed
if (0 != strcmp(settings->filename, previous_frame->filename)) {
fclose(settings->file_pointer);
settings->file_pointer = fopen(previous_frame->filename, "r");
strcpy(settings->filename, previous_frame->filename);
}
fseek(settings->file_pointer, previous_frame->position, SEEK_SET);
settings->sequence_number = previous_frame->sequence_number;
// cleanups on return:
#ifdef NOTYET
// if this was a remap we're done
if (cblock->executing_remap)
ERP(remap_finished(-cblock->phase));
#endif
// a valid previous context was marked by an M73 as auto-restore
if ((context_status &
(CONTEXT_RESTORE_ON_RETURN|CONTEXT_VALID)) ==
(CONTEXT_RESTORE_ON_RETURN|CONTEXT_VALID)) {
// NB: this means an M71 invalidate context will prevent an
// auto-restore on return/endsub
restore_settings(settings, settings->call_level + 1);
}
// always invalidate on leaving a context so we dont accidentially
// 'run into' a valid context when growing the stack upwards again
active_frame->context_status &= ~CONTEXT_VALID;
}
settings->sub_name = 0;
if (previous_frame->subName) {
settings->sub_name = previous_frame->subName;
} else {
settings->sub_name = NULL;
}
} else { // call_level == 0
logDebug("UNEXPECTED state %s: unhandled event=%s cl=%d rl=%d",
call_phases[active_frame->state], o_ops[event],
settings->call_level, settings->remap_level);
status = INTERP_ERROR;
// // a definition
// if (eblock->o_type == O_endsub) {
// CHKS((settings->defining_sub != 1), NCE_NOT_IN_SUBROUTINE_DEFN);
// // no longer skipping or defining
// if (settings->skipping_o) {
// logOword("case O_endsub in defn -- no longer skipping to:|%s|",
// settings->skipping_o);
// settings->skipping_o = NULL;
// }
// settings->defining_sub = NULL;
// settings->sub_name = NULL;
// }
}
break;
case CS_START: // not in a call
switch (event) {
case O_return:
case O_endsub:
// a definition
if (eblock->o_type == O_endsub) {
CHKS((settings->defining_sub != 1), NCE_NOT_IN_SUBROUTINE_DEFN);
// no longer skipping or defining
if (settings->skipping_o) {
logOword("case O_endsub in defn -- no longer skipping to:|%s|",
settings->skipping_o);
settings->skipping_o = NULL;
}
settings->defining_sub = NULL;
settings->sub_name = NULL;
}
active_frame->state = CS_DONE;
break;
default:
logDebug("state %s: unhandled event=%s cl=%d rl=%d",
call_phases[active_frame->state], o_ops[event],
settings->call_level, settings->remap_level);
status = INTERP_ERROR;
}
break;
default: default:
logDebug("unhandled state %s event %s cl=%d rl=%d", logDebug("state %s unhandled, event=%s cl=%d rl=%d",
o_ops[event], call_phases[active_frame->state], call_phases[active_frame->state], o_ops[event],
settings->call_level, settings->remap_level); settings->call_level, settings->remap_level);
status = INTERP_ERROR; status = INTERP_ERROR;
} }
} while ((status == INTERP_OK) && (active_frame->state != CS_DONE)); } while ((status == INTERP_OK) &&
(active_frame->state != CS_DONE) &&
(active_frame->state != CS_EXECUTING_BODY));
if (active_frame->state == CS_DONE)
active_frame->state = CS_START; // rewind fsm
return status; return status;
} }
@ -1047,7 +1219,7 @@ Returned Value: int (INTERP_OK)
Side effects: Side effects:
Changes the flow of control. Changes the flow of control.
Called by: execute_block Called by: execute
Calls: control_skip_to Calls: control_skip_to
control_back_to control_back_to
@ -1076,6 +1248,9 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
return INTERP_OK; return INTERP_OK;
} }
// if skipping_o was set, we are now on a line which contains that O-word.
// if skipping_to_sub was set, we are now on the 'O-name sub' definition line.
switch (block->o_type) { switch (block->o_type) {
case O_none: case O_none:
@ -1089,12 +1264,8 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
// if we were skipping, no longer // if we were skipping, no longer
if (settings->skipping_o) { if (settings->skipping_o) {
logOword("sub(o_|%s|) was skipping to here", settings->skipping_o); logOword("sub(o_|%s|) was skipping to here", settings->skipping_o);
// skipping to a sub means that we must define this now // skipping to a sub means that we must define this now
CHP(control_save_offset( block, settings)); CHP(control_save_offset( block, settings));
}
if (settings->skipping_o) {
logOword("no longer skipping to:|%s|", settings->skipping_o); logOword("no longer skipping to:|%s|", settings->skipping_o);
settings->skipping_o = NULL; // this IS our block number settings->skipping_o = NULL; // this IS our block number
} }
@ -1106,12 +1277,13 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
settings->parameters[2], settings->parameters[2],
settings->parameters[3]); settings->parameters[3]);
} else { } else {
logOword("started a subroutine defn: %s",block->o_name); // a definition. We're on the O<name> sub line.
// a definition logOword("started a subroutine defn: %s",block->o_name);
CHKS((settings->defining_sub == 1), NCE_NESTED_SUBROUTINE_DEFN); CHKS((settings->defining_sub == 1), NCE_NESTED_SUBROUTINE_DEFN);
CHP(control_save_offset( block, settings)); CHP(control_save_offset( block, settings));
settings->skipping_o = block->o_name; // start skipping // start skipping to the corresponding ensub.
settings->skipping_o = block->o_name;
settings->skipping_start = settings->sequence_number; settings->skipping_start = settings->sequence_number;
settings->defining_sub = 1; settings->defining_sub = 1;
settings->sub_name = block->o_name; settings->sub_name = block->o_name;
@ -1121,8 +1293,8 @@ int Interp::convert_control_functions(block_pointer block, // pointer to a block
case O_endsub: case O_endsub:
case O_return: case O_return:
// this will also leave_context() including appropriate actions
CHP(call_fsm(settings, block->o_type)); CHP(call_fsm(settings, block->o_type));
// CHP(execute_return(settings, NORMAL_RETURN)); same thing
break; break;
case O_call: case O_call: