More work on auto-evaluation

This commit is contained in:
claudiol 2018-03-27 13:03:34 -04:00
parent bd97380808
commit e7038dd055
6 changed files with 156 additions and 244 deletions

View file

@ -1041,7 +1041,7 @@ void rplDoAutoEval(WORDPTR varname,WORDPTR *indir)
WORD attr=rplGetIdentAttr(var[1]);
if(attr&IDATTR_DEPEND) {
var=rplFindGlobalPropInDir(varname,IDPROP_DEPN,indir,0);
var=rplFindGlobalPropInDir(*stkptr,IDPROP_DEPN,indir,0);
if(var) {
// EXPLODE THE DEPENDENCY LIST ON THE STACK
if(ISLIST(*var[1])) {
@ -1084,6 +1084,7 @@ void rplDoAutoEval(WORDPTR varname,WORDPTR *indir)
// DONE CREATING LIST OF VARIABLES THAT NEED TO BE RECALCULATED
// IS THIS REALLY A PROBLEM?
if(*stksave!=ScratchPointer1) {
// THE MAIN VARIABLE WAS MOVED DOWN THE LIST!
// THIS MEANS CIRCULAR REFERENCE
@ -1093,4 +1094,52 @@ void rplDoAutoEval(WORDPTR varname,WORDPTR *indir)
}
// NOW DO ->NUM ON THE 'CALC' PROPERTY OF ALL VARIABLES ON THE LIST AND STORE THEIR RESULTS
stkptr=stksave+1;
while(stkptr<DSTop) {
// FIND VARIABLE 'CALC' PROPERTY
// CHECK IF THE VARIABLE HAS DEPENDENCIES
var=rplFindGlobalInDir(*stkptr,indir,0);
if(var && (IDENTHASATTR(*var[1])) ) {
WORD attr=rplGetIdentAttr(var[1]);
if(attr&IDATTR_CALC) {
WORDPTR varcalc=rplFindGlobalPropInDir(*stkptr,IDPROP_CALC,indir,0);
if(varcalc) {
// FOUND A FORMULA OR PROGRAM, IF A PROGRAM, RUN XEQ THEN ->NUM
// IF A FORMULA OR ANYTHING ELSE, ->NUM
rplPushData(varcalc[1]);
WORDPTR stkcheck=DSTop;
if(ISPROGRAM(*varcalc[1])) rplRunAtomic(CMD_OVR_XEQ);
if(Exceptions) {
rplBlameError(varcalc[0]); // AT LEAST SHOW WHERE THE ERROR CAME FROM
if(DSTop>stksave) DSTop=stksave;
return;
}
rplRunAtomic(CMD_OVR_NUM);
if(Exceptions) {
rplBlameError(varcalc[0]); // AT LEAST SHOW WHERE THE ERROR CAME FROM
if(DSTop>stksave) DSTop=stksave;
return;
}
// WE GOT THE RESULT ON THE STACK
if(DSTop!=stkcheck) {
rplError(ERR_BADARGCOUNT);
rplBlameError(varcalc[0]); // AT LEAST SHOW WHERE THE ERROR CAME FROM
DSTop=stksave;
return;
}
// STORE THE NEW RESULT AND CONTINUE
var[1]=rplPopData();
}
}
}
++stkptr;
}
// ALL VARIABLES WERE RECOMPUTED
DSTop=stksave;
}

View file

@ -478,7 +478,6 @@ void LIB_HANDLER()
case UNPROTECTSTACK:
{
//@SHORT_DESC=@HIDE
// THIS INTERNAL OPCODE PROVIDES SAFETY GUARD AGAINST DATA STACK PROTECTION
// IF A PROGRAM FORGETS TO UNPROTECT THE STACK, IT WILL BE UNPROTECTED
// AUTOMATICALLY ON EXIT

View file

@ -194,7 +194,7 @@ void libFindMsg(BINT message,WORDPTR table);
// IDENTIFIER ATTRIBUTES USED BY THE SYSTEM
#define IDATTR_AUTOEVAL 1 // VARIABLE HAS A FORMULA/PROGRAM THAT NEEDS TO BE REEVALUATED
#define IDATTR_CALC 1 // VARIABLE HAS A FORMULA/PROGRAM THAT NEEDS TO BE REEVALUATED
#define IDATTR_DEPEND 2 // VARIABLE HAS DEPENDENT VARIABLES THAT NEED TO BE RECALCULATED IF ITS VALUE CHANGED
#define IDATTR_PREFUNIT 4 // VARIABLE HAS A PREFERRED SET OF UNITS FOR DISPLAY
#define IDATTR_FORCEUNIT 8 // IF UNIT IS NOT GIVEN, APPLY THE PREFERRED UNIT

View file

@ -226,6 +226,7 @@ void rplWarmInit();
void rplHotInit();
void rplSetEntryPoint(WORDPTR ip);
BINT rplRun();
BINT rplRunAtomic(WORD opcode);
void rplCleanup();
void rplDisableSingleStep();
void rplEnableSingleStep();
@ -503,7 +504,8 @@ void rplStoreSettingsbyName(BYTEPTR name, BYTEPTR nameend, WORDPTR object);
WORDPTR rplGetSettings(WORDPTR nameobject);
WORDPTR rplGetSettingsbyName(BYTEPTR name, BYTEPTR nameend);
// AUTOMATIC EVALUATION
void rplDoAutoEval(WORDPTR varname,WORDPTR *indir);

View file

@ -495,258 +495,86 @@ BINT rplRun(void)
BINT rplRunAtomic(WORD opcode)
// TAKE THE NEXT WORD AND EXECUTE IT
{
LIBHANDLER han;
// SAVE THE CURRENT EXECUTION STREAM
WORDPTR *rstksave=RSTop;
rplPushRet(IPtr);
WORDPTR obj=rplAllocTempObLowMem(2);
if(obj) {
obj[0]=Opcode;
obj[1]=CMD_ENDOFCODE;
obj[2]=CMD_QSEMI; // THIS IS FOR SAFETY REASONS
han=rplGetLibHandler(LIBNUM(opcode));
if(han) {
// EXECUTE THE OTHER LIBRARY DIRECTLY
BINT SavedOpcode=CurOpcode;
CurOpcode=opcode;
(*han)();
if(CurOpcode==opcode) CurOpcode=SavedOpcode;
}
else {
rplError(ERR_MISSINGLIBRARY);
return 0;
}
BINT rsave,lamsave,nlambase,retvalue;
WORD exceptsave,errcodesave;
// PRESERVE VARIOUS STACK POINTERS
if((RSTop>=rstksave) &&(IPtr==rstksave[0])) return 0; // EXECUTION WAS ATOMIC
rplSetExceptionHandler(0); // SAVE CURRENT EXCEPTION HANDLERS
rplPushRet(IPtr); // SAVE THE CURRENT INSTRUCTION POINTER
// IPtr WAS CHANGED, THEREFORE EXECUTION NEEDS TO CONTINUE
rsave=RSTop-RStk; // PROTECT THE RETURN STACK
lamsave=LAMTop-LAMs; // PROTECT LAM ENVIRONMENTS
nlambase=nLAMBase-LAMs;
rplSetEntryPoint(obj);
do {
RPLLastOpcode=CurOpcode=*IPtr;
retvalue=rplRun();
if(retvalue) {
if(Exceptions&(EX_POWEROFF|EX_HALT|EX_HWHALT|EX_HWBKPOINT|EX_HWBKPTSKIP)) {
if(!HaltedIPtr) return;
han=rplGetLibHandler(LIBNUM(CurOpcode));
// UN-PAUSE ALL HARDWARE BREAKPOINTS. THIS IS NEEDED FOR breakpt_seco ONLY.
BreakPtFlags&=~BKPT_ALLPAUSED;
if(han) (*han)();
else {
rplError(ERR_MISSINGLIBRARY);
// INVALID OPCODE = END OF EXECUTION (CANNOT BE TRAPPED BY HANDLER)
return NEEDS_CLEANUP;
// CONTINUE HALTED EXECUTION
if(RSTop>=HaltedRSTop) {
IPtr=HaltedIPtr-1;
RSTop=HaltedRSTop;
if(LAMTop>=HaltedLAMTop) LAMTop=HaltedLAMTop;
if(nLAMBase>=HaltednLAMBase) nLAMBase=HaltednLAMBase;
HaltedIPtr=0;
if(HWExceptions&EX_HWBKPOINT) HWExceptions|=EX_HWBKPTSKIP; // SKIP ONE SO AT LEAST IT EXECUTES ONE OPCODE
}
Exceptions|=HWExceptions;
if(Exceptions) {
if(HWExceptions) HWExceptions&=EX_HWBKPOINT; // CLEAR ANY EXCEPTIONS EXCEPT CHECK FOR BREAKPOINTS
if(Exceptions&EX_HWBKPOINT) {
if(!HaltedIPtr && !(Exceptions&~(EX_HWBKPOINT|EX_HWBKPTSKIP))) { // MAKE SURE WE DON'T HALT ALREADY HALTED CODE OR INTERFERE WITH OTHER EXCEPTIONS
// CHECK FOR BREAKPOINT TRIGGERS!
int trigger=0;
if(GET_BKPOINTFLAG(0)&BKPT_ENABLED) {
if(GET_BKPOINTFLAG(0)&BKPT_LOCATION) {
WORDPTR nextopcode=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
if((nextopcode>=BreakPt1Pointer)&&(nextopcode<rplSkipOb(BreakPt1Pointer))) {
if(!(Exceptions&EX_HWBKPTSKIP)) trigger=1;
}
} else if(!(Exceptions&EX_HWBKPTSKIP)) trigger=1;
if(trigger) {
if(GET_BKPOINTFLAG(0)&BKPT_COND) {
// HALT CURRENT PROGRAM
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
// PAUSE ALL HARDWARE BREAKPOINTS UNTIL CONDITION IS EXECUTED
BreakPtFlags|=BKPT_ALLPAUSED;
// PREPARE TO EXECUTE THE CONDITION - MUST BE A SECONDARY
rplPushDataNoGrow(BreakPt1Arg);
IPtr=(WORDPTR)bkpoint_seco;
CurOpcode=0;
Exceptions=0; // CLEAR ERRORS AND GO...
} else {
// HALT CURRENT PROGRAM
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
Exceptions=EX_HALT;
}
}
}
// TODO: ADD SAME CODE FOR BREKPOINTS 1 AND 2 HERE
if(!trigger && (GET_BKPOINTFLAG(1)&BKPT_ENABLED)) {
if(GET_BKPOINTFLAG(1)&BKPT_LOCATION) {
WORDPTR nextopcode=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
if((nextopcode>=BreakPt2Pointer)&&(nextopcode<rplSkipOb(BreakPt2Pointer))) {
if(!(Exceptions&EX_HWBKPTSKIP)) trigger=1;
}
} else if(!(Exceptions&EX_HWBKPTSKIP)) trigger=1;
if(trigger) {
if(GET_BKPOINTFLAG(1)&BKPT_COND) {
// HALT CURRENT PROGRAM
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
// PAUSE ALL HARDWARE BREAKPOINTS UNTIL CONDITION IS EXECUTED
BreakPtFlags|=BKPT_ALLPAUSED;
// PREPARE TO EXECUTE THE CONDITION - MUST BE A SECONDARY
rplPushDataNoGrow(BreakPt2Arg);
IPtr=(WORDPTR)bkpoint_seco;
CurOpcode=0;
Exceptions=0; // CLEAR ERRORS AND GO...
} else {
// HALT CURRENT PROGRAM
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
Exceptions=EX_HALT;
}
}
}
if(!trigger && (GET_BKPOINTFLAG(2)&BKPT_ENABLED)) {
if(GET_BKPOINTFLAG(2)&BKPT_LOCATION) {
WORDPTR nextopcode=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
if((nextopcode>=BreakPt3Pointer)&&(nextopcode<rplSkipOb(BreakPt3Pointer))) {
if(!(Exceptions&EX_HWBKPTSKIP)) trigger=1;
}
} else if(!(Exceptions&EX_HWBKPTSKIP)) trigger=1;
if(trigger) {
// SINGLE STEP BREAKPOINT DISABLES ITSELF AFTER IT'S TRIGGERED
SET_BKPOINTFLAG(2,GET_BKPOINTFLAG(2)&(~BKPT_ENABLED));
if(GET_BKPOINTFLAG(2)&BKPT_COND) {
// HALT CURRENT PROGRAM
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
// PAUSE ALL HARDWARE BREAKPOINTS UNTIL CONDITION IS EXECUTED
BreakPtFlags|=BKPT_ALLPAUSED;
// PREPARE TO EXECUTE THE CONDITION - MUST BE A SECONDARY
rplPushDataNoGrow(BreakPt3Arg);
IPtr=(WORDPTR)bkpoint_seco;
CurOpcode=0;
Exceptions=0; // CLEAR ERRORS AND GO...
} else {
// HALT CURRENT PROGRAM
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
Exceptions=EX_HALT;
}
}
}
} else {
// CHECK IF WE ARE DONE WITH THE BREAKPOINT CONDITION ROUTINE
// WARNING!!!: DO NOT MODIFY bkpoint_seco WITHOUT FIXING THIS!!
if(IPtr==bkpoint_seco+11) {
// WE REACHED THE END OF CODE STATEMENT, THEREFORE THE BREAKPOINT WAS TRIGGERED
// UN-PAUSE ALL HARDWARE BREAKPOINTS
BreakPtFlags&=~BKPT_ALLPAUSED;
// JUST STAY HALTED AND ISSUE A BREAKPOINT
Exceptions=EX_HALT;
}
}
Exceptions&=~(EX_HWBKPOINT|EX_HWBKPTSKIP);
if(!Exceptions) {
IPtr+=1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
continue;
}
}
// HARD EXCEPTIONS FIRST, DO NOT ALLOW ERROR HANDLERS TO CATCH THESE ONES
if(Exceptions&EX_EXITRPL) {
Exceptions=0;
rplClearRStk(); // CLEAR THE RETURN STACK
rplClearLAMs(); // CLEAR ALL LOCAL VARIABLES
ErrorHandler=0;
return CLEAN_RUN; // DON'T ALLOW HANDLER TO TRAP THIS EXCEPTION
}
if(Exceptions&EX_HWHALT) {
// HARDWARE-CAUSED HALT
// EMULATE THE HALT INSTRUCTION HERE
if(!HaltedIPtr) { // CAN'T HALT WITHIN AN ALREADY HALTED PROGRAM!
// SAVE THE ADDRESS OF THE NEXT INSTRUCTION
HaltedIPtr=IPtr+1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
HaltedRSTop=RSTop; // SAVE RETURN STACK POINTER
HaltednLAMBase=nLAMBase;
HaltedLAMTop=LAMTop;
Exceptions|=EX_HALT; // CONVERT TO A NORMAL HALT
}
}
if(Exceptions&EX_HALT) { rplSkipNext(); return CODE_HALTED; } // PREPARE TO RESUME ON NEXT CALL
if(Exceptions&EX_POWEROFF) { rplSkipNext(); return CODE_HALTED; } // PREPARE AUTORESUME
if(ErrorHandler) {
// ERROR WAS TRAPPED BY A HANDLER
rplCatchException();
}
else {
// THERE IS NO ERROR HANDLER --> UNTRAPPED ERROR
// SAVE THE EXCEPTIONS FOR ERRN AND ERRM
TrappedExceptions=Exceptions; // THE ERROR HANDLER CAN KNOW THE EXCEPTIONS BY LOOKING AT THIS VARIABLE
// ExceptionPointer STILL POINTS TO THE WORD THAT CAUSED THE EXCEPTION
TrappedErrorCode=ErrorCode;
return NEEDS_CLEANUP; // END EXECUTION IMMEDIATELY IF AN UNHANDLED EXCEPTION IS THROWN
}
Exceptions=0;
continue;
}
else // STOP EXECUTION ON OTHER EXCEPTIONS
break;
}
} while(retvalue);
// SKIP TO THE NEXT INSTRUCTION / OBJECT BASED ON CurOpcode
// NOTICE THAT CurOpcode MIGHT BE MODIFIED BY A LIBRARY HANDLER TO ALTER THE FLOW
IPtr+=1+((ISPROLOG(CurOpcode))? OBJSIZE(CurOpcode):0);
// MANUAL RESTORE
} while(1);
if(RSTop>=RStk+rsave) RSTop=RStk+rsave; // IF RSTop<RStk+rsave THE RETURN STACK WAS COMPLETELY CORRUPTED, SHOULD NEVER HAPPEN BUT...
else rplCleanup();
if(LAMTop>=LAMs+lamsave) LAMTop=LAMs+lamsave; // OTHERWISE THE LAM ENVIRONMENTS WERE DESTROYED, SHOULD NEVER HAPPEN BUT...
else rplCleanup();
if(nLAMBase>=LAMs+nlambase) nLAMBase=LAMs+nlambase; // OTHERWISE THE LAM ENVIRONMENTS WERE DESTROYED, SHOULD NEVER HAPPEN BUT...
else rplCleanup();
// RESTORE THE ERROR CODES FIRST, TO CAPTURE ANY ERRORS DURING POPPING THE RETURN STACK
exceptsave=Exceptions;
errcodesave=ErrorCode;
Exceptions=0;
// RESTORE THE IP POINTER
IPtr=rplPopRet();
// AND THE ERROR HANDLERS
rplRemoveExceptionHandler();
Exceptions=exceptsave;
Errorcode=errcodesave;
if(Exceptions) ExceptionPointer=IPtr;
// IF EVERYTHING WENT WELL, HERE WE HAVE THE SAME ENVIRONMENT AS BEFORE
// IF SOMETHING GOT CORRUPTED, WE SHOULD HAVE AN INTERNAL EMPTY RSTACK ERROR
return retvalue;
}
return 0;
}

View file

@ -0,0 +1,34 @@
<button collapse="ovr-operators" block="true" >**Overloadable operators** <badge>26</badge> <badge>3 NEW</badge></button>
<collapse id="ovr-operators" collapsed="true">
^ Operator ^ Short Description ^ ^
| **Evaluation operators:** |||
| **[[manual:chapter6:operators:cmd_ovr_eval1|EVAL1]]** | Evaluate one level | <badge>NEW</badge> |
| **[[manual:chapter6:operators:cmd_ovr_eval|EVAL]]** | Evaluate full depth | |
| **[[manual:chapter6:operators:cmd_ovr_xeq|XEQ]]** | Execute | <badge>NEW</badge> |
| **[[manual:chapter6:operators:cmd_ovr_num|→NUM]]** | Compute numeric result | |
| **Test operators:** |||
| **[[manual:chapter6:operators:cmd_ovr_eq|==]]** | Equality test | |
| **[[manual:chapter6:operators:cmd_ovr_noteq|≠]]** | Not equal test | |
| **[[manual:chapter6:operators:cmd_ovr_lt|<]]** | Less than test | |
| **[[manual:chapter6:operators:cmd_ovr_lte|≤]]** | Less than or equal test | |
| **[[manual:chapter6:operators:cmd_ovr_gt|>]]** | Greater than test | |
| **[[manual:chapter6:operators:cmd_ovr_gte|≥]]** | Greater than or equal test | |
| **[[manual:chapter6:operators:cmd_ovr_cmp|CMP]]** | Comparison test (<0 if A<B, 0 if A==B, >0 if A>B) | <badge>NEW</badge> |
| **[[manual:chapter6:operators:cmd_ovr_same|SAME]]** | Comparison test, true if objects are the same | |
| **[[manual:chapter6:operators:cmd_ovr_istrue|ISTRUE]]** | True test | <badge>NEW</badge> |
| **Logical operators:** |||
| **[[manual:chapter6:operators:cmd_ovr_and|AND]]** | Logical AND | |
| **[[manual:chapter6:operators:cmd_ovr_or|OR]]** | Logical OR | |
| **[[manual:chapter6:operators:cmd_ovr_xor|XOR]]** | Logical XOR | |
| **[[manual:chapter6:operators:cmd_ovr_not|NOT]]** | Logical NOT | |
| **Mathematic operators:** |||
| **[[manual:chapter6:operators:cmd_ovr_add|+]]** | Addition | |
| **[[manual:chapter6:operators:cmd_ovr_sub|-]]** | Subtraction | |
| **[[manual:chapter6:operators:cmd_ovr_mul|*]]** | Multiplication | |
| **[[manual:chapter6:operators:cmd_ovr_div|/]]** | Division | |
| **[[manual:chapter6:operators:cmd_ovr_pow|^]]** | Power | |
| **[[manual:chapter6:operators:cmd_ovr_xroot|XROOT]]** | Root | |
| **[[manual:chapter6:operators:cmd_ovr_inv|INV]]** | Inverse | |
| **[[manual:chapter6:operators:cmd_ovr_neg|NEG]]** | Negate/change sign| |
| **[[manual:chapter6:operators:cmd_ovr_abs|ABS]]** | Magnitude or absolute value | |
</collapse>