Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 08:37 12 Jul 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : CMM2 how to load and execute a second basic programm

Author Message
digger72
Newbie

Joined: 07/02/2021
Location: Germany
Posts: 4
Posted: 12:32pm 09 Jan 2025
Copy link to clipboard 
Print this post

Hello together.

In MMBasic exists the EXECUTE command with which I can execute Basic commands. Unfortunately, this only works for single commands and not for complete Basic files from SD card. Is there a way to load and execute a second Basic program within my program and to return after its end?

Many thanks in advance for any help.

Best regards, Frank
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7865
Posted: 01:02pm 09 Jan 2025
Copy link to clipboard 
Print this post

Hi Frank, and welcome to the 'shed. :)

I think
EXECUTE "RUN myfilename$"
does something like that on the CMM2. I've not tried it. I've not tried this on a PicoMite.

You can use RUN "myfile$" from within a program, of course. All variables are destroyed and myfile$ can't be a variable, I don't think.

On the PicoMite you can use FLASH CHAIN (which preserves variables), but you can't CHAIN anything else.

.
Edited 2025-01-09 23:06 by Mixtel90
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
digger72
Newbie

Joined: 07/02/2021
Location: Germany
Posts: 4
Posted: 01:25pm 09 Jan 2025
Copy link to clipboard 
Print this post

yeah i tried this, but "RUN" removes the active program and runs the new one. after this is finished there is no way to return to the previous state from before.

The second Basic program should work like a dynamic loaded external function/extension at runtime. My use case is to start external tools from inside my application.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10240
Posted: 01:28pm 09 Jan 2025
Copy link to clipboard 
Print this post

This isn't possible with MMBasic. Loading a program overwrites the variable space of the previous program
 
digger72
Newbie

Joined: 07/02/2021
Location: Germany
Posts: 4
Posted: 01:38pm 09 Jan 2025
Copy link to clipboard 
Print this post

  matherp said  This isn't possible with MMBasic. Loading a program overwrites the variable space of the previous program


Yes, i understand, thats why RUN is not the right choice. The EXECUTE command does perfetly what i need, but only for one single command. I need the possibility to load some more Basic lines from an external file and execute them in the context of my running program. a loop with EXECUTE for all loaded Basic lines does not work for more complex code or functions/subroutines.

Maybe there exist a trick to load an external Basic program and appending this to the running program?
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7865
Posted: 01:46pm 09 Jan 2025
Copy link to clipboard 
Print this post

No. To add to a program it would have to be in the editor. That's simply not possible as the editor has used up the variables area.

I'm afraid that what you are asking for isn't possible. Once a program is running there is no way to change it without ending it as the editor doesn't exist.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
PeteCotton

Guru

Joined: 13/08/2020
Location: Canada
Posts: 543
Posted: 03:37pm 09 Jan 2025
Copy link to clipboard 
Print this post

  digger72 said   I need the possibility to load some more Basic lines from an external file and execute them in the context of my running program. a loop with EXECUTE for all loaded Basic lines does not work for more complex code or functions/subroutines.

Maybe there exist a trick to load an external Basic program and appending this to the running program?



Hear me out here - this might be a bit of a mad solution - and I haven't tried it - but here goes.

STEP 1:

You have your program called "MainProgram" and you have the second program called "SubProgram".

Create an empty file called "SubProgram.inc"

In MainProgram, at the start, put the following lines:
 
 GOTO StartOfSubProgram
ReturnHere:
 ' Delete SubProgram.inc
 OPEN "SubProgram.inc" FOR OUTPUT AS #1
 PRINT #1, ""
 CLOSE #1

Now at the very end of your program put the lines:

StartOfSubProgram:
 #INCLUDE "SubProgram.inc"
 GOTO Returnhere:


STEP 2:

When you want to run SubProgram, copy the contents of "SubProgram.bas" to a new file called "SubProgram.inc", then run "MainProgram" again using the command:
EXECUTE "RUN " + CHR$(34) + "MainProgram.bas" + CHR$(34)

This will restart your program, but now the sub program is attached to the end. Your program will jump to the start of the subprogram and execute it.

Of course, it will only return control to your MainProgram if it runs off the end of the sub program, but you could also search SubProgram.Inc for the END command (and not END IF/END SUB etc.) and change that to "GOTO ReturnHere".

Even if this works (I'm not sure that it will), you will have to be careful that all of your variables and subs in the MainProgram are unique from the SubProgram - so I would prefix them all with an unusual set of characters e.g. "TD45_Variable".

Also, you will lose any variables in memory on the restart - however you could save them to a disk file and reload them when the program restarts.

This is all a bit hacky - but hey - at least I found a good use for the GOTO command!
Edited 2025-01-10 01:39 by PeteCotton
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4038
Posted: 03:46pm 09 Jan 2025
Copy link to clipboard 
Print this post

You would pretty much need an OS but there isn't one.  (hmm, it would probably prevent what you ask for, anyway.)

And on almost all of the supported devices there isn't enough memory either (the CMM2 is an exception).

I suppose you could restructure MMBasic...

Maybe move to Windows or Linux as then at least you have an OS and may have such as system(), though it may also not quite do what you want.

BTW some of the ideas floated would only work if MMBasic doesn't tokenise things ahead of execution i.e. if it's a typical interpreter not a semi-compiler.

John
Edited 2025-01-10 01:49 by JohnS
 
Andy-g0poy
Regular Member

Joined: 07/03/2023
Location: United Kingdom
Posts: 75
Posted: 05:03pm 09 Jan 2025
Copy link to clipboard 
Print this post

I would think that you could do something to make this work, but it will need careful design.

The "main" program would need to very carefully keep a record of all of it's variables. When you need to run the second program you write these variables to a file.

Then you execute and run the  second file when finished you then run the first program again and load the variables etc from the file. You would need to manage the first start carefully, but it would not be too hard.


HOWEVER

this is pretty much what FLASH CHAIN does. It runs another program leaving the variables intact.
 
is this not good enough for your needs?

Page 35 of the manual I have

There is also the Flash Filesystem drive A: which might be useful

Andy
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7865
Posted: 06:14pm 09 Jan 2025
Copy link to clipboard 
Print this post

Wrong machine, Andy. He's on about the CMM2, which doesn't have either flash slots or a A: drive in flash.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2610
Posted: 08:52pm 09 Jan 2025
Copy link to clipboard 
Print this post

Last year I did something similar (it was on a Pico but should work on a CMM2).

When the main program started it looked for a Sub containing initializing values. If not found it Saved itself to a disk file then generated and appended lines to the end of the copy.

These were two subroutines, the one held all the variable values the program would need when re-run and the other all the new data that it would need. (In your case that subroutine would contain the new commands.)

It then RUN the disk file.

See footnote in this post here.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9593
Posted: 12:30am 10 Jan 2025
Copy link to clipboard 
Print this post

I thought that the CMM series had the CHAIN command?
Perhaps that was only on the CMM1 and earlier FW, and perhaps that command was removed from MMBASIC by the time the CMM2 came on the scene.....
Smoke makes things work. When the smoke gets out, it stops!
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2610
Posted: 02:13am 10 Jan 2025
Copy link to clipboard 
Print this post

  Quote  SD Card and File Related Commands
There is no drive B: in the Colour Maximite 2. The SD card is drive A:.
The command CHAIN is not implemented. The Colour Maximite 2 has an exceptionally large program memory space so this feature is not necessary.
The library and the LIBRARY commands are not implemented and not needed on the Colour Maximite 2.
Instead of using these commands you can use #INCLUDE to insert files into the program at run time

So using the method in my previous post the program would copy (SAVE fname$) itself to A: then append a Sub containing the #INCLUDE command.
It would then RUN fname$ and at the appropriate point call the Sub. Precede the call with On Error Skip to prevent an error on the first run which won't have the Sub.
Edited 2025-01-10 12:27 by phil99
 
digger72
Newbie

Joined: 07/02/2021
Location: Germany
Posts: 4
Posted: 07:54am 10 Jan 2025
Copy link to clipboard 
Print this post

Thanks for your help.

@phil99 I will experiment a little with your suggestion. Thank you.

GEOS for the C64 is a good example of the principle. A basic application runs and within this application you can start PAINT, WRITE or any other sub-programme.
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7865
Posted: 08:26am 10 Jan 2025
Copy link to clipboard 
Print this post

The C64 (as most home computers) has its editor and BASIC interpreter in ROM at all times and the user program space is all RAM area. This makes such tricks relatively easy. The RAMTOP address is stored in RAM, so you can change that to move the top of the RAM area lower. BASIC will still run as its variables are usually stored at RAMTOP-some figure or other. It will just have less user space to run in. The empty RAM area can then be loaded with a second program.

MMBasic does not work in this way. The editor is effectively a transient program that uses the variables area to store the program being edited in plain ASCII. After editing the program is pre-processed to handle #INCLUDE and tokenize it before it can be run. The plain ASCII copy of the program is replaced by the variables.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 4302
Posted: 10:12am 10 Jan 2025
Copy link to clipboard 
Print this post

Interesting Mick, I've never thought about it before, but I guess that is how it might work on '80s micro-computers. MMBasic could have done it that way too, but it doesn't and I don't see that changing ever.

Should anyone care the approach I'm currently using where a "shell" program want to RUN a "child" program and then be returned to is for the shell program to write its name into a file called "A:/.mmbasic-shell" and then pass the command line argument --shell to the "child" program. On exit the "child" checks MM.CMDLINE$ and if --shell is present will RUN the "shell" program.

This doesn't address restoring the state of the "shell" program which should I feel it necessary I would achieve through writing/reading state to files.

Note that @matherp the enhanced END command in the very latest PicoMite versions to provide an alternative method of returning to a shell (by running a command on program exit), but it isn't available on the CMM2 or MMB4L (yet) so I chose not to make use of it.

Also there are issues if/when the shell is run from FLASH in which case you don't have a value for MM.INFO(CURRENT) to write into ".mmbasic-shell".


' Reads the '.mmbasic-shell' file.
'
' @param  exist%  If 1 then ERROR if file does not exist, otherwise return empty string.
' @param  fnbr%   File number to use for accessing the file, if unspecified/0 then uses #9.
' @return         The contents of the first line of the file.
Function sys.read_shell_file$(exist%, fnbr%)
 Const f$ = sys.HOME$() + "/.mmbasic-shell"
 If Not exist% And Not Mm.Info(Exists f$) Then Exit Function
 Const _fnbr% = Choice(fnbr%, fnbr%, 9)
 Open f$ For Input As _fnbr%
 Line Input #_fnbr%, sys.read_shell_file$
 Close _fnbr%
End Function

' Writes the '.mmbasic-shell' file for later reading by sys.run_shell().
'
' @param  s$     Contents to write to the file, if empty then writes path of current program.
' @param  fnbr%  File number to use for accessing the file, if unspecified/0 then uses #9.
Sub sys.write_shell_file(s$, fnbr%)
 Const f$ = sys.HOME$() + "/.mmbasic-shell"
 Const _s$ = Choice(s$ = "", Mm.Info(Current), s$)
 Const _fnbr% = Choice(fnbr%, fnbr%, 9)
 If sys.read_shell_file$(0, _fnbr%) <> _s$ Then
   ' Only write if content has changed.
   Open f$ For Output As _fnbr%
   Print #_fnbr%, _s$
   Close _fnbr%
 EndIf
End Sub

' Runs the program specified by the '.mmbasic-shell' file.
'
' @param  fnbr%  File number to use for accessing the file, if unspecified/0 then uses #9.
Sub sys.run_shell(fnbr%)
 Const prog$ = sys.read_shell_file$(1, fnbr%)
 If prog$ <> "" Then Run prog$
End Sub


Best wishes,

Tom
MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7865
Posted: 11:34am 10 Jan 2025
Copy link to clipboard 
Print this post

In Microsoft BASIC and its relatives the program grows upward from the endpoint of the system variables area. That means that the system variables are always at fixed addresses. RAMTOP (or HIMEM? or something like that) on some systems is actually requested when BASIC is started, so that the user has the opportunity to lower it. Program variables are in a stack that works down from HIMEM so the more variables you use the less program area you have. This is where the housekeeping comes in in BASIC. Every so often the system cleans up the variables stack to optimize the program area. If it doesn't do this then eventually the variables will hit the program! Unfortunately this takes a little time to do. MMBasic doesn't need to do this as the variables area is separate from the program space.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025