Hi!
hjalfi wrote:
I did have a couple of questions here:
- when doing offline compilation, it's essentially just dumping the bytecode to disk with the standalone interpreter on the front. But, the bytecode produced by the IDE will be at a different address than the bytecode used by the standalone interpreter. It looks like the bytecode contains fixed addresses, so how is relocation done? (This is important for me because CP/M-65 uses relocatable binaries. Just writing a chunk of memory out to disk isn't going to work as it may need to be loaded at a different address.)
The compiler simply calculates a "relocation offset" and adds it to any address reference when generating code, see
https://github.com/dmsc/fastbasic/blob/ ... s.asm#L604 . To emit relocatable code, all the locations with addresses could be stored to emit the relocation table later.
hjalfi wrote:
- the compiler looks like it's single-pass. How are forward references resolved? Does it just not need them --- i.e. with symbols declared on first use and with no procedure parameter checking?
Yes, the compiler is single pass, but there are two types of forward references supported:
1- When emitting loops, the address of the jump instruction is pushed to a loop stack, and when the loop end is parsed, the address is pop-ed from the stack and patched with the correct destination. This allows this code:
Code:
WHILE A : .... do something ... : WEND
to be converted to
Code:
loop_2:
LOAD A
CJUMP loop_1
.... do something ...
JUMP loop_2
loop_1:
.....
(labels are not bytecodes, only addresses stored by the parser)
2- When calling PROCedures, the parser search the address of the procedure implementation in a table, if it is missing a new entry is created, marked as "undefined" and the address of the caller is stored there. When the procedure is declared afterwards, all the undefined entries are patched with the real address. At the end of the parsing, if the table has any undefined entry, an error is produced.
Currently the 6502 compiler does not check that the number of parameters of the procedure matches between calls, bit the cross compiler do count the parameters and errors out on mismatches.
hjalfi wrote:
- how are you handling string management, i.e. something like a$ = a$ + "1"? I don't see a heap or a garbage collector.
Strings are handled like original Turbo Pascal strings: allocated on first use, and always of 256 bytes. There are internally two types of strings, similar to the C L-values and R-values. An L-value string is a pointer to 256 bytes of memory, but R-values can point to any shorter strings, like string constants or string produced by internal functions (like "STR$" or "CHR$").
To simplify the parser, string concatenation is currently abbreviated as A$ =+ "1" , this simply calls a "string append" function passing the two addresses.
hjalfi wrote:
- it's less of a question and more of a statement, but local variables in procedures would be really nice...
Yes!
The problem is my goal of full IDE under 8kB, and I'm already about 50 bytes over my budget
Also, one big gotcha of the language is that procedure parameters are also global variables, so this code swaps X and Y:
Code:
X=1 : Y=2
@Swap X,Y
? X,Y
PROC Swap Y,X : ENDPROC
At call time, X and Y are pushed to the stack, then at the start of the procedure, both are pop-ed from the stack and assigned to Y and X respectively, so the values are swapped.
hjalfi wrote:
Quote:
If you omit the editor, you could build the compiler and interpreter without the need of the cross-compiler.
Isn't the standalone compiler also written in Basic? e.g. cmdline.bas.
Yes, but the code is fairly simple, so rewriting it in assembler is a simple task. The very first versions of FastBasic did that, as the cross compiler did not exist yet.
hjalfi wrote:
There does seem to be a fair amount of Atari stuff which needs unpicking from e.g. the editor but I don't think that would be hard. The worst part will be generating CP/M-65 binaries. I did try telling cc65 to produce o65 output files, which I should then be able to convert, but the linker failed miserable with a whole pile of error messages. There is a way around this but it's annoying and I'm not sure I can make it work with your build system, so I might have to hack some other build system up.
IMHO, it would be simpler to write a new output format to LD65. I already add the "Atari XEX" output format, and it was fairly simple, so I expect that adding the CP/M-65 format would not be that hard.
hjalfi wrote:
I'm also intrigued as to whether it might be possible to use this as the basis for a standard Comal system; it's already very nearly the same language, and it should mostly be a matter of rewriting the syntax files...
Yes, the good thing about BASIC is that many people like it, specially in older 6502 systems, it is a natural fit for the small machines.
What would be difficult to implement in the current FastBasic is functions, because the parser assumes that some registers are not changed inside any expression, and the stack is very small.
Have Fun!