6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 10:40 am

All times are UTC




Post new topic Reply to topic  [ 7 posts ] 
Author Message
PostPosted: Fri Jan 24, 2003 6:20 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
leeeeee wrote:
kc5tja wrote:

EhBASIC uses a neat-o CALL mechanism that works reasonably well enough for this type of expansion, but again, it's not seamless.



Want to make some suggestions then? I'm always open to ideas from users (or potential users).


NOTE -- Taken from General Discussion forum.

Not particularly; the suggestions I'd make would make the language much less portable, since the language would then subsume the role of a command shell as well. It's best to let a more seamless system interface be part of the user's specific installation/port of EhBASIC. This way, EhBASIC is still appealing to those who wish to run a traditional CP/M-type or Unix-type shell environment.

It would involve, for example, creating two new types of variables: command references and function references. A command variable is invoked in a manner similar to PRINT, while a function variable is invoked similarly to USR(). The code to which they point to cannot be changed by normal BASIC functionality; instead, new operators must be added to ensure type agreement and extraction (e.g., myCmd = CMDPTR(49152) sets myCmd to point to $C000. Now you can say myCmd a,b,c or whatever. Saying myCmd = 49152 would either give an error, or change the type of myCmd to integer -- not something you want to have happen. :) To print the current address of myCmd, you'd need something like PRINT CMDADR(myCmd) or some such. For functions, it'd be like: myFunc = FNPTR(49152):z = myFunc(a,b,c):PRINT FNADR(myFunc)).

Then it would involve making use of the aforementioned system, internally, to implement the command syntax. If a command would normally produce a syntax error because it wasn't found as an intrinsic of the language (or a pre-existing command variable), the BASIC would have to scan the command-path of the interpretter on disk to find the command with the appropriate name. If found, it'd have to load it into memory, and assign a command variable to point to it automatically. Then it'd invoke the command using the normal command variable conventions. The same would be true for functions as well.

I don't think people would want to wait for the interpretter to get through scanning the disk every time an unrecognized command appeared (particularly annoying on machines with only a single floppy disk drive). :)

As you can see, this is a non-trivial change, and while it is quite possible to do (and is perhaps even useful for systems equipped with fast secondary storage; a harddrive or flash ROM access on a syntax error wouldn't be nearly as bad as a floppy access), I'm not sure I'd want this to be part of your core EhBASIC system.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Jan 24, 2003 9:03 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
usotsuki wrote:
How about a command like "AUTOSHELL ON" or "AUTOSHELL OFF" and then allow manual execution of external commands by a "SHELL" command (BASICA 2 style) ? :รพ


That would work, I suppose.

BTW, moving this specific discussion (re: EhBASIC) to the EhBASIC forum.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 27, 2003 12:44 pm 
Offline

Joined: Fri Aug 30, 2002 2:05 pm
Posts: 347
Location: UK
kc5tja wrote:
instead, new operators must be added to ensure type agreement and extraction (e.g., myCmd = CMDPTR(49152) sets myCmd to point to $C000. Now you can say myCmd a,b,c or whatever.


You can already do something similar like this ..
Code:
10 mc=$C000 : REM machine code command address
.
.
100 CALL mc,a,b,c

.. it just needs your routine to interpret the ',a,b,c' and return with the BASIC execute pointer updated correctly.

kc5tja wrote:
For functions, it'd be like: myFunc = FNPTR(49152):z = myFunc(a,b,c):PRINT FNADR(myFunc)).


The USR() function is probably one of the most ignored functions in BASIC because of it's clunky use. I've been thinking of changing it to allow the address to be passed along with the first arguament. So you could do ..
Code:
10 mc=$C000 : REM machine code function address
.
.
100 x=USR(mc,a,b,c)

.. this time mc would be evaluated and, on seeing the comma, held as the execute address. A would be evaluated and the result placed in the first floating accumulator as per the current USR() function syntax. ',b,c' and any other values would, if present, need to be evaluated by the users code.

kc5tja wrote:
Then it would involve making use of the aforementioned system, internally, to implement the command syntax. If a command would normally produce a syntax error because it wasn't found as an intrinsic of the language (or a pre-existing command variable), the BASIC would have to scan the command-path of the interpretter on disk to find the command with the appropriate name


kc5tja wrote:
As you can see, this is a non-trivial change, and while it is quite possible to do (and is perhaps even useful for systems equipped with fast secondary storage; a harddrive or flash ROM access on a syntax error wouldn't be nearly as bad as a floppy access), I'm not sure I'd want this to be part of your core EhBASIC system.


The two biggest hurdles to this approach are that EhBASIC only recognises the first two letters of a variable or function name as unique. This is deliberate and makes handling of variables and functions easier but would, without major changes, make handling external command and function names difficult. There is also that EhBASIC, being an interpreter, tokenises all code lines before executing them so embedded keywords would get crunched inappropriately.

There's no reason why CALL and USR() couldn't be used to call the shell from within the BASIC environment but, as you say, this (the shell) is not a portable feature.

I did think briefly about using the 'Syntax Error' to pass control, via a user changeable vector or similar, but the flow mess that is EhBASIC doesn't lend itself to this approach at all.

Cheers

Lee.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 27, 2003 8:21 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
leeeeee wrote:
You can already do something similar like this ..
Code:
10 mc=$C000 : REM machine code command address
.
.
100 CALL mc,a,b,c


My point is that (a) you don't need the explicit CALL keyword, and (b) the variable is used as a keyword. So your example would look like this:

Code:
mc = CMDPTR($C000)
mc a,b,c


Quote:
The USR() function is probably one of the most ignored functions in BASIC because of it's clunky use. I've been thinking of changing it to allow the address to be passed along with the first arguament. So you could do ..


One of the reasons it's so clunky is because you do have to keep worrying about addresses, and the fact that USR() doesn't say what the function does (except that it's a user-defined function).

Quote:
...this time mc would be evaluated and, on seeing the comma, held as the execute address.


Situational logic like this is what makes BASIC the number one most detested language in all of computer science and engineering. In no uncertain terms, BASIC is not a proper programming language. It's a collection of bandaids that lets the user do programming-related tasks. This was as true when it was first introduced back in the 60s as it is today.

I do not mean this as an insult to you, or to any BASIC programmer. It's just that having a language construct behave differently depending on whether or not a comma follows a parameter has been proven time and again to be a huge source of bugs and programmer grief.

Quote:
command and function names difficult. There is also that EhBASIC, being an interpreter, tokenises all code lines before executing them so embedded keywords would get crunched inappropriately.


That's why you have new variable types to handle addresses. These become variable names, and therefore can be tokenized just like regular variable names.

When first tokenizing a line, if the unidentified keyword isn't already a command or function variable, this is when BASIC will try to load the command into memory, and create a variable for it. (After all, BASIC auto-creates unidentified variables when you first use them!)

Quote:
There's no reason why CALL and USR() couldn't be used to call the shell from within the BASIC environment but, as you say, this (the shell) is not a portable feature.


The whole point of the discussion is that BASIC **IS** the shell. How can USR() be used to call "the shell" when it already IS the shell?

As I said, BASIC really isn't an appropriate language to do this sort of thing with. Oberon is actually built with this kind of usage in mind (it's extremely modular). Forth requires minimal amounts of boiler-plate to do it, but the syntax of the language is so regular that it might be worth it. This is why I advocated using Forth as the basic system software: it's expected that people will load their favorite languages from disk. 9 out of 10 people will probably not ever use that Forth environment. But for those who lose their boot-disk, or whatever, the Forth environment provides a very low-overhead, fully functional language environment that allows the computer to continue to be used productively, instead of just sitting there, repeating the message "Non-system disk. Press any key" all the time.

There's nothing quite like paying $900 for a genuine AMD Athlon or Intel Pentium IV Xeon-based, 512MB IBM PC-compatible paperweight with the latest nVidia GeForce 4 chipset video card. I don't spend $15000 for a new car, only to have to load the engine in it every time I want to use it. It comes with a perfectly good engine on its own. If I want something better, then and only then will I replace the engine.

Hmm...I'm not sure I can express this clearer, and I get the distinct feeling that I've probably offended a few people here. So I'll stop now while I'm still ahead. :)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Jan 27, 2003 10:49 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
> I did think briefly about using the 'Syntax Error' to pass control, via a
> user changeable vector or similar, but the flow mess that is EhBASIC
> doesn't lend itself to this approach at all.

Lee, I haven't used your BASIC yet, but it looks like you've really done a good job on it. I hope it gets used widely in 6502 systems. So nothing I say should be misconstrued as criticism in the bad sense, only ideas from someone who has never tried to write a BASIC but has been spoiled on the fantastic one in my Hewlett-Packard hand-held HP-71 computer, which is much, much nicer than HP's BASIC they run on their bigger computers (which I've also used). The first 64K of it came with the mainframe, and I have another 200K or so of extensions in plug-in modules and in LEX (Language EXtension) files from the user groups in RAM, so obviously it's not expected that it would all be carried out on a 6502. That's not to say I haven't gotten a lot of good ideas from these HP hand-held computers however, which I have used in my 65K work.

Upon line entry, the HP-71 finds most syntax errors that other BASICs would miss until they try to run the program. In fact the parser is so good you can enter a line with everything run together with no spaces, and in most cases it can figure it all out. For run-time error-handling, it has the normal ON ERROR GOTO/GOSUB, where the error routine can check for the error type with ERRL (error line), ERRN (error number), or ERRM$ (error message string). The error descriptions are rather precise too, leaving less to guesswork. When the program or subprogram calls another subprogram in the same program or in another RAM-resident program (of which there could be many), the ON ERROR is saved as part of the local environment and is not carried into the called subprogram.

Without the user's having to resort to assembly language, the concept of the BASIC subprogram may provide for much of the issues being discussed. The subprogram has its own environment, so it can use variable A, for example, without stepping on any variable A used by the calling program or subprogram. This allows for recursion too, BTW. The subprogram's name is descriptive because you call it by label instead of line number. There can be any number of inputs and outputs, all passed by way of the parentheses where the subprogram is called.

But on another topic, the system has hooks so built-in things aren't stuck with built-in behavior. Take for example * , the normal BASIC multiplying operator. The mainframe only had * for real numbers, both integers and floating-point of different precisions. When you add the math module with its big LEX file, * now also works for complex numbers as if it were originally written for them. There's no need for a new operator. In the statement C=A+B, A and/or B can be complex variables if C is too.

To anticipate a couple of questions: The LEX files are written in assembly and do not present the performance penalty of using higher-level language to simulate things that are better left to assembly. They are automatically incorporated into the BASIC system upon power-up. The non-serious user may lament the fact that a firm understanding of, and strict adherence to system rules is imperative to avoid corrupting things or crashing the computer. Also, about using labels: Yes, the label search slows things down, but only the first time. Then the address offset is compiled so subsequent runs only have to verify that the label is still where it was expected. If it got moved since the last run, then yes, a new label search will be done. BTW, I should mention that in this system you woudn't want to use addresses. RAM contents are unaffected by puting the computer asleep (you never do really turn it off), and programs are in files in the RAM. You can have hundreds of files there at once. If a program deletes or resizes a file at a lower address and memory is moved down to close up the gap, absolute addresses suddenly change. (This is not true of the basic BASIC kernel itself or of its handling of Forth, which get left in place.) The operating system does a lot of memory-moving, but it's transparent to the user. I've hardly ever noticed any delays from memory-moving. Files never get fragmented like they do on disc.

The subprogram is called with CALL <name> <optional parameter list>. The subprogram, defined in BASIC, is started with SUB <descriptive name> <optional parameter list> and typically ended with ENDSUB.

Garth


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 28, 2003 10:33 am 
Offline

Joined: Fri Aug 30, 2002 2:05 pm
Posts: 347
Location: UK
kc5tja wrote:
My point is that (a) you don't need the explicit CALL keyword, and (b) the variable is used as a keyword.


EhBASIC isn't nearly clever enough to do that. There is always some explicit marker to tell the interpreter what to do with a name.

kc5tja wrote:
leeeeee wrote:
...this time mc would be evaluated and, on seeing the comma, held as the execute address.


Situational logic like this is what makes BASIC the number one most detested language in all of computer science and engineering.


Which says as much about computer scientists and engineers as it does BASIC.

kc5tja wrote:
That's why you have new variable types to handle addresses. These become variable names, and therefore can be tokenized just like regular variable names.


Variable names don't get tokenised. That's what makes them distinct from BASIC keywords.

kc5tja wrote:
When first tokenizing a line, if the unidentified keyword isn't already a command or function variable, this is when BASIC will try to load the command into memory, and create a variable for it.


The line parser isn't that clever and anyway all variables are destroyed when the program is edited. (I could have changed that but there is no overall advantage.)

kc5tja wrote:
(After all, BASIC auto-creates unidentified variables when you first use them!)


BASIC only creates a variable when you assign a value to it. If the first line of a program says ..
Code:
 10 A=B+C

.. only A gets created. B and C either return a null value of their type or, with a small change to BASIC, return an 'Undefined variable' error.

kc5tja wrote:
As I said, BASIC really isn't an appropriate language to do this sort of thing with.


Looking at the changes needed I would have to agree. Fortunate really that I never intended it for that.

kc5tja wrote:
Hmm...I'm not sure I can express this clearer, and I get the distinct feeling that I've probably offended a few people here. So I'll stop now while I'm still ahead. :)


Don't worry on my count, I'm too thick skinned to offend easily. 8^)=

Lee.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Jan 28, 2003 11:21 am 
Offline

Joined: Fri Aug 30, 2002 2:05 pm
Posts: 347
Location: UK
GARTHWILSON wrote:
Lee, I haven't used your BASIC yet, but it looks like you've really done a good job on it. I hope it gets used widely in 6502 systems.


I suspect it is used by more people than let on. I usually only find out if they have a problem with it. 8^)=

..And on the subject of wide use, last night I got it to run on a satellite receiver. The Thomson SRB1 DMAC receiver uses the ITT CCU3000 which is a 65C02 with onboard peripherals and some RAM. I've grafted in a 6551 for I/O to the host and some extra RAM for now but, once I've worked out how to use the receivers on screen graphics and data port, I plan to just have the extra RAM and an EPROM on a 'drop in' board into the current EPROM socket.

GARTHWILSON wrote:
So nothing I say should be misconstrued as criticism in the bad sense, only ideas from someone who has never tried to write a BASIC but has been spoiled on the fantastic one in my Hewlett-Packard hand-held HP-71 computer,


I've used many BASICs on many machines. What I've aimed for is the most usefull features in the least space. I got fed up with 'full featured' tiny BASICS that weren't (variables A to Z only, no strings, no arrays and no floating point math) and the more powerfull Microsoft type were too system dependant to port easily between hardware.

Some commands and functions have been stolen from compiled BASICs, VARPTR(), SADD(), DO and LOOP for example, and some stolen from tiny BASICs or even assembler, like the bit operators and functions.

GARTHWILSON wrote:
Without the user's having to resort to assembly language, the concept of the BASIC subprogram may provide for much of the issues being discussed. The subprogram has its own environment, so it can use variable A, for example, without stepping on any variable A used by the calling program or subprogram. This allows for recursion too, BTW.


I did think of implementing procedures as in BBC BASIC complete with local variables but in the end decided that the performance penalty (not to mention the actual writing of the code 8^)= ) was not worth the effort.

On a side note the function variable in a user defined function is local to the function definition. So in ..
Code:
10 DEF FNa(x)=1/SQR(x)
20 x=PI
30 PRINT FNa(2)
40 PRINT x

.. x would still be 3.141593 at line 40 and not 2 as you may expect.

One thing I am thinking of adding is direct assembler support, though how this is to be implemented I have yet to decide. I'm also thinking of adding HIMEM and LOWMEM as both commands and functions and getting rid of the 'Memory size' prompt at cold start.

Then there's the remaining 'undocumented features' to either document or remove. 8^)=

Lee.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: