Certain BASIC functionality is optional in ScarletDME and these are toggled by using the $MODE statement followed by a mode. Some examples of this are:
CASE.SENSITIVE - Enables case sensitivity
OPTIONAL.FINAL.END - Suppress warning messages if there is no END at the end
I want to add the TIME.MS option which will let the TIME() function get the milliseconds fraction as well as the seconds. This is something that is in a later version of qm but isn't in ScarletDME.
I already have the op_timems function that returns the correct time in seconds and milliseconds.
I have also already added that opcode following the steps in my previous post about adding a function:
⇒ Adding a Function to ScarletDME
In this post I'll focus on just the MODE specific stuff.
I need to first add the TIME.MS mode to the BASIC compiler, GPL.BP/BCOMP, and then I also need to check that mode and switch between op_time and op_timems based on the mode.
Adding the mode looks to be straightforward. The modes are all defined in the same place and so I can add my mode here as well.
* Values of mode (Bit positions)
...
$define M.NO.CASE.INVERT 20
$define M.OPTIONAL.THEN.ELSE 21; *rdm
$define M.TIME.MS 22
** End New Modes
Now we also need to add it to the list of mode names:
...
mode.names := @VM:"NO.CASE.INVERT"
mode.names := @VM:"OPTIONAL.THEN.ELSE"
mode.names := @VM:"TIME.MS"
This sets up the skeleton work so that we can test for the TIME.MS mode.
Now that we have the mode, we can use the same check used elsewhere to check for the TIME.MS mode.
An example of this can be found around line 3940.
if not(bittest(mode, M.CASE.SENSITIVE)) then define.token = upcase(define.token)
This test is for the case sensitivity but the one I'm doing for TIME.MS will be similar.
This area is where the tokens are looped over and checked to see if the are an intrinsic and if they should trigger an intrinsic function. I'm going to add a check here for M.TIME.MS and then based on that change the intrinsic.
This is very similar to what the M.CASE.SENSITIVE mode is doing.
if bittest(mode, M.CASE.SENSITIVE) then x.symbol.name = upcase(symbol.name)
else x.symbol.name = symbol.name
if bittest(mode, M.TIME.MS) then
locate 'TIME' in intrinsics<1> by 'AL' setting i then
intrinsic.opcodes<i> = OP.TIMEMS
end
end else
locate 'TIME' in intrinsics<1> by 'AL' setting i then
intrinsic.opcodes<i> = OP.TIME
end
end
Now I haven't figured out why trying to compile the qmsys in the ScarletDME working folder doesn't update the gcat properly. Luckily I do have a work around.
I copy the modified BCOMP to my system's qmsys and then compile it with the internal account.
cp qmysys/GPL.BP/BCOMP /usr/qmsys/GPL.BP
Now we can compile BCOMP making sure to use the qm Internal account.
cd /usr/qmsys/
bin/qm -Internal
> BASIC GPL.BP BCOMP
Once compiled, I then copy the gcat/$BCOMP to my working directory so that I can push it to github.
cp /usr/qmsys/gcat/\$BCOMP ~/bp/ScarletDME/qmsys/gcat
We can make sure that everything works by trying some test routines:
PRINT TIME()
END
This will print just the seconds after midnight.
$MODE TIME.MS
PRINT TIME()
END
We should now see the seconds with a millisecond fractional part!
We can also update the $BASIC.OPTIONS with our new mode:
X
MODE TIME.MS
This way any programs compiled in the future will use the millisecond version instead of the regular TIME function.
With that we have a working version of ScarletDME with a brand new mode!