|
Forum Index : Microcontroller and PC projects : Chain Command
| Author | Message | ||||
James_From_Canb![]() Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
If you're chaining programs and using a pointer to keep track of what programs to run from your menu or master program, don't initialise the pointer in the master program - it will get overwritten. Chaining looks like a really useful feature. James Here's a short example: ' a program to show how the Chain command can be used.
' We rely on MMBasic initialising numeric variables to 0. ' Each chained program increments the value of counter ' that tracks where we are up to. ' If we initialised the counter to 0 in code, it will continually ' get reset and overwrite the values updated by the chained programs. ? "UpTo counter is:"; UpTo If UpTo = 0 then [2 lines added] OPTION Base 1 ' must be set before any DIM statements False = 0 : True = 1 ' if done here, only performed once. CHAIN "Chain0.bas" ElseIf UpTo = 1 then CHAIN "Chain1.bas" Elseif UpTo = 2 then CHAIN "Chain2.bas" Else ? "Finished" endif ' Chain0.bas
? "In Chain0.bas" UpTo = UpTo + 1 CHAIN "chn-demo.bas" ' back to calling program END ' Chain1.bas
? "In Chain1.bas" UpTo = UpTo + 1 CHAIN "chn-demo.bas" ' back to calling program END ' Chain2.bas
? "In Chain2.bas" UpTo = UpTo + 1 CHAIN "chn-demo.bas" ' back to calling program END [added] Also, some things can only be run once, and must be run before other commands, like Option Base 1 must be declared before any dimensioning is done. For efficiency, some things should only be done once, like setting False = 0. If you set variables, declare option base, etc, in the program at the top of the chain, do it after the test for the first run (see added lines in the first code example). My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
| Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3308 |
A neat solution but why would you want to keep chaining back to the first program? Each module could chain direct to the next module as you can use chain an unlimited number of times. I can see that you would need to return to a main program if it held a menu that was used to select the module that ran next. But then you would not need a counter as the menu entry would select the module. Geoff Geoff Graham - http://geoffg.net |
||||
James_From_Canb![]() Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
A good question with a couple of answers. I was taught to program in hierarchies and it's a habit now. I was converting large chunks of code and it made testing easier if I could enable and disable modules quickly from a single control program. It was working out how to implement 'include' code, where a file of code is executed and the program has to work out where to return to in the calling program. And it was an interesting issue to look at. James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
James_From_Canb![]() Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
Two more points about chaining: You need to provide the program name as a string i.e. chain "nextprog.bas", whereas the rest of MMBasic no longer needs the quote marks around the program name. A program that is chained to it has its own MM.CMDLINE$, but you can't pass parameters to a program you're chaining to. For example: ParamsIn$ = MM.CMDLINE$ CHAIN "nextprog.bas" ParamsIn$ and CHAIN "nextprog.bas ParamsIn$" don't work. This means the program chained to always has an empty MM.CMDLINE$. You cannot use the chained program like a black box function called by multiple programs and controlled by command line parameters. It's easy enough to work around though. The chained program needs to be modified to work with a saved copy of the original MM.CMDLINE$ (like ParamsIn$ above). Anyway, they're both trivial really - but noting them, especially the second point, might save someone else the trouble of working them out by trial and error like I did. And I reckon the chain command it the best thing since sliced bread. James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
| shoebuckle Senior Member Joined: 21/01/2012 Location: AustraliaPosts: 189 |
One thing that occurs to me with Chaining is that the Chained-to program cops all the baggage (variables) from the chaining program. This can be a problem if you want to chain two programs originally developed as stand alone applications, such as Renumber and Format. One really needs to vacate much of the space used by the Chaining program. Wouldn't it be nice if you could pass only the variables the chained program needed so that you had the whole memory space available in the Chained-to program. Granted, you could individually ERASE array variables that are not needed to recover space but you don't have that option with other variables. You could also pass the variables needed via a file. e.g. CHAIN filename[.bas] [variable] [,variable]... [,#Filenumber] [,#Filenumber]... If the filename is followed by a list of variables and files, then all the others in the chaining program are deleted and closed. If the list is absent then all are carried forward as at present. (Sorry Geoff... more work, if you think it worth while!! :-) ) Cheers, Hugh |
||||
James_From_Canb![]() Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
I've emailed Geoff with a possible bug involving Chaining. At least there's an easy workaround. If you read data values in a program and then chain to another, the pointer that keeps track of the data values isn't being cleared when the second program starts. The consequence is that the second program does not start reading the data values from the beginning of the first line of data in the second program. If that sounded a little convoluted, here's the example code I sent Geoff to demonstrate the issue. ' this program demonstrates a possible bug in the chain command.
' The pointer that tracks the next DATA element to be read ' causes unexpected results when the CHAIN command is used. ' DIM ARR1$(6) DATA "Data1", "Data2", "Data3", "Data4", "Data5", "Data6" For i = 1 to 4 ' only 4 of the 6 in this test Read ARR1$(i) PRINT "Main program saved value "; ARR1$(i) next i CHAIN "TestChn.bas" And TestChn.bas is ' Part 2 of a program to demonstrate a potential bug with the CHAIN command.
' DIM ARR2$(6) DATA "P2Data1", "P2Data2", "P2Data3", "P2Data4", "P2Data5", "P2Data6" For i = 1 to 6 Read ARR2$(i) PRINT "Chained program saved value "; ARR2$(i) next i END TestChn.bas reads in P2Data5 and P2Data6 then gives an error because there is no more data to read. It gives a similar error if the first program reads in all 6 data values. The workaround is to use the RESTORE statement at the start of the second program. This resets the pointer. James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
| djuqa Guru Joined: 23/11/2011 Location: AustraliaPosts: 447 |
Why depend on embedded DATA values when you should be reading the values from a DATA file. If the program is complex/ big enough to need to be chained in sections, then data statements would be had to justify. VK4MU MicroController Units |
||||
| shoebuckle Senior Member Joined: 21/01/2012 Location: AustraliaPosts: 189 |
Ah! The problem arose when chaining to an existing program. James_From_Canb and I have been working on Chaining his Renumber program to my Format. Both programs use DATA statements internally for their own purposes. The Data from Renumber's DATA statements is not used by Format. Cheers, Hugh |
||||
| djuqa Guru Joined: 23/11/2011 Location: AustraliaPosts: 447 |
Suppose it is my programming background (I learned assembly,pascal,c before I learned BASIC), but I have never seen the need/advantage/usage of DATA statements VK4MU MicroController Units |
||||
| shoebuckle Senior Member Joined: 21/01/2012 Location: AustraliaPosts: 189 |
You ought to try it some time. It's a very convenient way of providing a program with a small amount of constant data and it has the advantage of making the program self-contained (doesn't depend upon the presence of an external data file). However, I have to agree with you that it is better to use a file if the data is volatile or if there is a lot of it. In Format I use data statements to provide a list of Operators and Basic Commands that Format needs to parse a line of code. There are only a small number (12 out of 201) commands which affect formatting and only 9 operators to check so it makes sense to load the Command$() and Operator$() arrays from DATA statements. On the other hand, in Crunch that I am developing, I need to be able to check against all 201 commands so I load them from a Data file. Cheers, Hugh |
||||
| djuqa Guru Joined: 23/11/2011 Location: AustraliaPosts: 447 |
Not likely, It goes against all my experience,training and good MVC (Model,View,Controller i.e. Separation of CODE/Data) programming practice. But each to their own techniques. VK4MU MicroController Units |
||||
James_From_Canb![]() Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
They're Constants. Think of it like object oriented coding where each object (in this case a program or subroutine) contains the non-volatile data it will need. [ducks for cover and fits flame-proof suit]. James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
| djuqa Guru Joined: 23/11/2011 Location: AustraliaPosts: 447 |
No comment (puts the Petrol tin and matches back in the Shed) VK4MU MicroController Units |
||||
| BobD Guru Joined: 07/12/2011 Location: AustraliaPosts: 935 |
I seem to recall that Pascal has a type Constant which was used for setting fixed values just like a Data statement. |
||||
| Lopezjm2001 Regular Member Joined: 08/07/2012 Location: AustraliaPosts: 42 |
Hi all and Geoff Graham, I am using the CHAIN command with three files. The starting file is AUTO.BAS which will chain to either F5.BAS or F6.BAS depending on whether you press the F5 keyboard button or the F6 keyboard button. You start by typing: new [enter] load "AUTO.BAS" [enter] run [enter] t The t button allows the AUTO.BAS program to run as there is no CAN connected. The programs work fine after pressing the F5 or F6 button the first time but the second time no matter which button I press F5 or F6 I get this error: "Too many nested DO or WHILE loops" It seems that once a file is chained the mmbasic interpreter does not reset the number of loops. I am wondering whether it is a bug in the basic interpreter? Anyhow I have uploaded the three files. The files are lengthy. 2013-05-24_143142_CHAIN.zip Thanks, John Lopez Lopez |
||||
James_From_Canb![]() Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 265 |
John, Just to clarify, AUTO.BAS runs and chains to F5.BAS or F6.BAS, and these two programs run AUTORUN.BAS to get back? I'm ignoring the obvious problem that the original program is called auto.bas, not autorun.bas. Regards James My mind is aglow with whirling, transient nodes of thought careening through a cosmic vapor of invention. Hedley Lamarr, Blazing Saddles (1974) |
||||
| Geoffg Guru Joined: 06/06/2011 Location: AustraliaPosts: 3308 |
Damn, another bug
I will fix it in the next version. Geoff Geoff Graham - http://geoffg.net |
||||
| shoebuckle Senior Member Joined: 21/01/2012 Location: AustraliaPosts: 189 |
James_From_Canb, smart fellow that he is, pointed out a feature of MMBasic which is useful if you are having to Chain programs because you run out of memory. This is most likely to happen when using large string arrays and lots of string variables. It is most likely that you don't need many of these variables in the Chained-to program, and sometimes bugs can creep in because you use the same variable name in both programs and forget that it already contains data. Array variables are easy to remove using the ERASE command but all global variables carry across. The significant word here is "Global". Local variables do not carry across so James' suggestion is to make all but a short stub of the Chaining program a "Main" subroutine and define all the variables, including arrays, that you do NOT want to be carried forward to the Chained program as Local within Sub Main. Here is an example. Program Chain1.bas chains to Chain2.bas. Only variables Fname$, a, i, d$ and the array d(i) carry across and you will see that trying to print array variable e(1) in Chain2.bas causes an error because it hasn't come across and therefore hasn't been DIM'd. A very simple, neat solution. Thanks James. Hugh 'Chain1.bas
Fname$="Chain2.bas" a=10 Dim d(a) for i=1 to a d(i)=i next i=1 Main(a) Chain Fname$ End Sub Main(c) Local b,c$,e(c),i for i=1 to c e(i)=i Next c=c+2 b=c C$="Now is the time" d$=c$ End Sub 'Chain2.bas
Print "Fname$=",Fname$ Print "a=",a Print "b=",b Print "c=",c Print "c$=",c$ Print "d$=",d$ Print "i=",i Print "Array d="; For j=1 to 10 Print d(j); Next For j=1 to 10 Print e(j) Next |
||||
| Tinine Guru Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Chain? Does this still exist? I don't see it in the manual. |
||||
| twofingers Guru Joined: 02/06/2014 Location: GermanyPosts: 1672 |
Hi, I think it refers to MAXIMITES only. This thread is from 2013! Regards Michael causality ≠ correlation ≠ coincidence |
||||
| The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |