mirror of
https://github.com/dschmenk/PLASMA.git
synced 2025-03-24 13:35:24 +00:00
Merge branch 'master' of https://github.com/dschmenk/PLASMA
This commit is contained in:
commit
626274d100
@ -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.
|
||||
|
@ -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
|
||||
```
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user