From c3019689e2a2a6a33c38fdb9ccbe2fba066f0a63 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 25 Nov 2014 10:42:11 -0800 Subject: [PATCH 1/3] Fix multi-dimensional index example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8818d15..c22c67d 100644 --- a/README.md +++ b/README.md @@ -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. From dc2c7f1b4ecdded3843cc9cf21c2d64e055ab056 Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 25 Nov 2014 10:58:51 -0800 Subject: [PATCH 2/3] Add STRUC explanation and fix multidimensional array --- doc/User Manual.md | 48 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/doc/User Manual.md b/doc/User Manual.md index 6592259..86079f6 100644 --- a/doc/User Manual.md +++ b/doc/User Manual.md @@ -234,7 +234,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 +246,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 +262,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 +303,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 ``` From 78dbaecb3f9fa3e3aa7a15e038130ee98beb03dc Mon Sep 17 00:00:00 2001 From: David Schmenk Date: Tue, 25 Nov 2014 11:07:51 -0800 Subject: [PATCH 3/3] Add Structure Declaration --- doc/User Manual.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/User Manual.md b/doc/User Manual.md index 86079f6..4451d90 100644 --- a/doc/User Manual.md +++ b/doc/User Manual.md @@ -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.