[TI ASM] Parser and Compiler
Moderator: MaxCoderz Staff
[TI ASM] Parser and Compiler
I figured I'd move my topic over to here since it didn't really relate to the post it was in and maybe people would see it in here. So I'm writing a compiler for C/C++ for z80 asm (trying to do so anyways). I'm still working on the parsing code into abstract syntax trees, but it's coming along. Once I get that done I'll be working on actually translating it into asm code which might prove to be the most difficult part. I'm going to make my best effort to make the compiler smart about where it stores it's data and what not, but it'd be really helpful to me if the expert asm people could fill me in on any conventions for z80 asm. Are there certain registers usually used for calling arguements? Are registers callee saved, caller saved, or split between them? I would like to try and keep everything data in registers as much as possible, but this might prove to be challenging. Are there any conventions to storing data to memory? I need to know stuff like to make things run as best as possible.
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
There are no 'standard' registers used for calling arguments - you write your functions with certain input and output registers in mind - of course, this limits recursion.
Useful registers, however, are the index registers ix and iy. These index registers can be set to a particular value, then you can easily use them to read/write to memory via an offset - for example, ld a,(ix+5) or ld (iy-4),0
One 'easy' way (albeit inefficient) of calling functions would be to push all of the arguments onto the stack then call the function, and the function would then pop the arguments back off again (this makes recursion very simple).
However, as you have very limited stack-space, it might be better to store the arguments somewhere in RAM and only push a pointer to these variables to the stack before calling. You could then pop into IX and use the index registers to access the individual arguments.
Without wanting to sound entirely self-whoring, if you don't intend to write your own assembler, using Brass with nested modules and the .var/tvar directives would no doubt make allocating variables (local or otherwise) much simpler. (I have had, in the background, the idea of writing a C-ish compiler for the Z80, hence these features in Brass).
Useful registers, however, are the index registers ix and iy. These index registers can be set to a particular value, then you can easily use them to read/write to memory via an offset - for example, ld a,(ix+5) or ld (iy-4),0
One 'easy' way (albeit inefficient) of calling functions would be to push all of the arguments onto the stack then call the function, and the function would then pop the arguments back off again (this makes recursion very simple).
However, as you have very limited stack-space, it might be better to store the arguments somewhere in RAM and only push a pointer to these variables to the stack before calling. You could then pop into IX and use the index registers to access the individual arguments.
Without wanting to sound entirely self-whoring, if you don't intend to write your own assembler, using Brass with nested modules and the .var/tvar directives would no doubt make allocating variables (local or otherwise) much simpler. (I have had, in the background, the idea of writing a C-ish compiler for the Z80, hence these features in Brass).
I usually use a for bytes and and hl for words, if I need more I move on to b, c or de.Are there certain registers usually used for calling arguements?
Depends on the situation, I guess. And on who you ask.Are registers callee saved, caller saved, or split between them?
Yup, use the "saferams". 768 bytes at plotsscreen, 512 bytes at statvars, et cetera. But it isn't much, so you may need to use the free ram in the vat...Are there any conventions to storing data to memory?
Edit: Ah, well, cross-post...
Good thinking, BenHowever, as you have very limited stack-space, it might be better to store the arguments somewhere in RAM and only push a pointer to these variables to the stack before calling. You could then pop into IX and use the index registers to access the individual arguments.
http://clap.timendus.com/ - The Calculator Link Alternative Protocol
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
http://api.timendus.com/ - Make your life easier, leave the coding to the API
http://vera.timendus.com/ - The calc lover's OS
- benryves
- Maxcoderz Staff
- Posts: 3089
- Joined: Thu 16 Dec, 2004 10:06 pm
- Location: Croydon, England
- Contact:
The way I'd do it is I'd structure things so that different types have different rules.
The base types I'd at least start with would be byte, ubyte, short and ushort. Then I'd have different rules for the operators (for example, comparing a ubyte to a ubyte would be different to comparing a byte to a byte). Making sure that the types match up is imperative.
I'd have thought that not checking types makes your life more difficult and things unpredictable. I'd also make explicit casting between two different types that don't have an operator defined mandatory.
The base types I'd at least start with would be byte, ubyte, short and ushort. Then I'd have different rules for the operators (for example, comparing a ubyte to a ubyte would be different to comparing a byte to a byte). Making sure that the types match up is imperative.
I'd have thought that not checking types makes your life more difficult and things unpredictable. I'd also make explicit casting between two different types that don't have an operator defined mandatory.
-
- MCF Legend
- Posts: 1601
- Joined: Mon 20 Dec, 2004 8:45 am
- Location: Budapest, Absurdistan
- Contact:
The point of using types is having lots of potential errors caught at compile time and also producing more efficient executables. The type system is a fundamental building block of a language, and you should put a lot of thought into designing it. You have to define ranges, operations (including error conditions like overflow) and coercion rules with care. I'd include the following primitive types: signed and unsigned integers of 8, 16, 24 and 32 bits, fixed point numbers (multiplication and division need to be optimised for them in a special way) of various precisions, boolean (so the compiler knows it could as well be just a flag), character and string (self-managing). To describe composite data I'd only use arrays and records, maybe unions too.
And I think you should forget about C. It's too 'strong' a language in my opinion, that's why there is no efficient compiler for it to date. If I were to design a language for this platform, I'd constrain it as much as possible, e. g. I would probably avoid pointers (use much more restricted references instead) and goto (not for academic reasons; goto can really mess up optimisation), let alone objects, generics and other complex structures.
And I think you should forget about C. It's too 'strong' a language in my opinion, that's why there is no efficient compiler for it to date. If I were to design a language for this platform, I'd constrain it as much as possible, e. g. I would probably avoid pointers (use much more restricted references instead) and goto (not for academic reasons; goto can really mess up optimisation), let alone objects, generics and other complex structures.
- L4E_WakaMol-King
- Maxcoderz Staff
- Posts: 342
- Joined: Tue 01 Nov, 2005 6:34 am
That's ironic... we just went over parsing trees and compilers today in one of my classes. Good luck... it will be a hell of a lot of work.
- Now Under Development - [Progress]
I was shooting for C/C++/Java style. I'm just working on getting the basics going right now (operations, assignments, declarations, functions, basic statements). Deciding on specific types and what not doesn't need to be done now. I'm just parsing the given code text into an abstract syntax tree so that it's easy to translate and type check. Is there any reason not use this sort of style?
-
- MCF Legend
- Posts: 1601
- Joined: Mon 20 Dec, 2004 8:45 am
- Location: Budapest, Absurdistan
- Contact:
Certainly it's partly personal preference. To me it makes more sense to do it in this order:
1. Deciding on language features
2. Working out type system (and everything related)
3. Dealing with structure (scoping, blocks, interfaces...)
4. Describing the semantics of control constructs
5. Creating syntax (reserved words, delimiters, anything) and writing some example code
6. Generating parser (there are ready-made tools for this)
7. And now I can start thinking about compilation...
The first five steps are purely paperwork. Writing example code (simple applications or games) and running it in head (elaborately, tracking all the values generated including the implicit conversions and such) is a vital step, because it helps you discover design errors before jumping in the implementation phase.
1. Deciding on language features
2. Working out type system (and everything related)
3. Dealing with structure (scoping, blocks, interfaces...)
4. Describing the semantics of control constructs
5. Creating syntax (reserved words, delimiters, anything) and writing some example code
6. Generating parser (there are ready-made tools for this)
7. And now I can start thinking about compilation...
The first five steps are purely paperwork. Writing example code (simple applications or games) and running it in head (elaborately, tracking all the values generated including the implicit conversions and such) is a vital step, because it helps you discover design errors before jumping in the implementation phase.
Well I've never written a full compiler and parser and I'm not even that great at z80 asm so I'm just kinda playing it by ear and see what happens. If someone else wants to take a more serious shot at this, then by all means go for it. I'm mainly playing around with this cause it sparked my curiousity and I have some down time between semesters to play around with stuff. I haven't decided anything beyond the language will have operations, assignments, typical controls structures, some basic types (I'm not even working on implementing these yet cause I'm still just parsing stuff out into a syntax tree), and functions. I haven't gotten past reading in code from a file into my syntax tree. Once I do, then I'll worry about implementation of each feature including what types I want and how they are going to work.