1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2024-07-03 05:29:30 +00:00
This commit is contained in:
David Schmenk 2014-11-25 13:10:37 -08:00
commit 626274d100
2 changed files with 55 additions and 14 deletions

View File

@ -160,13 +160,13 @@ Functions are defined after all constants, variables and data. Functions can be
After functions are defined, the main code for the module follows. The main code will be executed as soon as the module is loaded. For library modules, this is a good place to do any runtime initialization, before any of the exported functions are called. The last statement in the module must be done, or else a compile error is issued.
There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a . character denotes a byte type, a : character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the . or : and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers. Multiple brackets can follow the . or : type identifier, but all but the last index will be treated as a pointer to an array.
There are four basic types of data that can be manipulated: constants, variables, addresses, and functions. Memory can only be read or written as either a byte or a word. Bytes are unsigned 8 bit quantities, words are signed 16 bit quantities. Everything on the evaluation stack is treated as a word. Other than that, any value can be treated as a pointer, address, function, character, integer, etc. There are convenience operations in PLASMA to easily manipulate addresses and expressions as pointers, arrays, structures, functions, or combinations thereof. If a variable is declared as a byte, it can be accessed as a simple, single dimension byte array by using brackets to indicate the offset. Any expression can calculate the indexed offset. A word variable can be accessed as a word array in the same fashion. In order to access expressions or constants as arrays, a type identifier has to be inserted before the brackets. a . character denotes a byte type, a : character denotes a word type. Along with brackets to calculate an indexed offset, a constant can be used after the . or : and will be added to the base address. The constant can be a defined const to allow for structure style syntax. If the offset is a known constant, using the constant offset is a much more efficient way to address the elements over an array index. Multidimensional arrays are treated as arrays of array pointers.
```
word hgrscan[] = $2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00
word = $2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80
hgrscan.[yscan][xscan] = fillval
hgrscan.[yscan, xscan] = fillval
```
Values can be treated as pointers by preceding them with a ^ for byte pointers, * for word pointers.

View File

@ -87,6 +87,23 @@ const bufflen = 2048
These constants can be used in expressions just like a variable name.
#### Structure Declarations
There is a shortcut for defining constant offsets into structures:
```
struc s_entry
word id
byte[32] name
word next_entry
end
```
is equivalent to:
```
const s_entry = 36 // size of the structure
const id = 0 // offset to id element
const name = 2 // offset to name element
const next_entry = 34 // offset to next_entry element
```
#### Predefined Functions
Sometimes a function needs to be referenced before it is defined. The `predef` declaration reserves the label for a function. The `import` declaration block also uses the `predef` declaration to reserve an external function. Outside of an `import` block, `predef` will only predefine a function that must be declared later in the source file, otherwise an error will occur.
@ -234,7 +251,7 @@ def hgrfill(val)
for yscan = 0 to 191
for xscan = 0 to 19
hgrscan:[yscan][xscan] = val
hgrscan:[yscan, xscan] = val
next
next
end
@ -246,7 +263,7 @@ def hgrfill(val)
for yscan = 0 to 191
for xscan = 0 to 39
hgrscan.[yscan][xscan] = val
hgrscan.[yscan, xscan] = val
next
next
end
@ -262,10 +279,31 @@ word = 2
byte = "PLASMA"
puti(myrec:0) // ID = 2
putc($8D) // Carriage return
puti(myrec.2) // Name length = 6 (Pascal string puts length byte first)
```
This contrived example shows how one can access offsets from a variable as either `byte`s or `word`s regardless of how they were defined. This operator becomes more powerful when combined with pointers, defined next.
#### Defining Structures
Structures can be defined so that the offsets are calculated for you. The previous example can be written as:
```
predef puti // print an integer
struc mystruc // mystruc will be defined as the size of the structure itself
word id
byte name // one byte for length, the number of characters are variable
end
byte myrec[]
word = 2
byte = "PLASMA"
puti(mystruc) // This will print '3', the size of the structure as defined
putc($8D) // Carriage return
puti(myrec:id) // ID = 2
putc($8D) // Carriage return
puti(myrec.name) // Name length = 6 (Pascal string puts length byte first)
```
#### Pointers
Pointers are values that represent addresses. In order to get the value pointed to by the address, one must 'dereference' the pointer. All data and code memory has a unique address, all 65536 of them (16 bits). In the Apple II, many addresses are actually connected to hardware instead of memory. Accessing these addresses can make thing happen in the Apple II, or read external inputs like the keyboard and joystick.
@ -282,24 +320,27 @@ end
```
Pointers to structures or arrays can be referenced with the `->` and `=>` operators, pointing to `byte` or `word` sized elements.
```
const elem_id = 0
const elem_addr = 1
struc record
byte id
word addr
end
def addentry(entry, id, addr)
entry->elem_id = id // set ID byte
entry=>elem_addr = addr // set address
return entry + 3 // return next enry address
def addentry(entry, new_id, new_addr)
entry->id = new_id // set ID (byte)
entry=>addr = new_addr // set address (word)
return entry + record // return next enry address
end
```
The above is equivalent to:
```
const elem_id = 0
const elem_addr = 1
const record_size = 3
def addentry(entry, id, addr)
(entry).elem_id = id // set ID byte
(entry):elem_addr = addr // set address
return entry + 3 // return next enry address
def addentry(entry, new_id, new_addr)
(entry).elem_id = new_id // set ID byte
(entry):elem_addr = new_addr // set address
return entry + record_size // return next enry address
end
```