From c8ff626943c7abb299b8a3c3f7e320968d6dc19c Mon Sep 17 00:00:00 2001 From: marcobaye Date: Sat, 31 May 2014 00:46:55 +0000 Subject: [PATCH] Release 0.94.12: Finally created new "!for" syntax so counting can start at zero. Added "0b" as alternative prefix for binary values. git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@33 4df02467-bbd4-4a76-a152-e7ce94205b78 --- docs/AllPOs.txt | 76 ++++++++++++++++++++++++------------ docs/Changes.txt | 10 +++++ docs/Errors.txt | 9 ++++- docs/QuickRef.txt | 17 ++++---- examples/trigono.a | 11 +++--- src/acme.c | 4 +- src/alu.c | 97 +++++++++++++++++++++++++--------------------- src/config.h | 2 +- src/flow.c | 61 +++++++++++++++++++++-------- 9 files changed, 181 insertions(+), 106 deletions(-) diff --git a/docs/AllPOs.txt b/docs/AllPOs.txt index b91706f..1d0d64e 100644 --- a/docs/AllPOs.txt +++ b/docs/AllPOs.txt @@ -115,12 +115,12 @@ conversion table file, try using ACME: !to "asc2pet.ct", plain ; no load address * = 0 ; pc = table index ; first create "as-is" table - !for i, 256 {!byte i - 1} + !for i, 0, 255 {!byte i} ; now exchange upper and lower case characters - * = 65 - !for i, 91 - 65 {!byte * + 128} - * = 97 - !for i, 123 - 97 {!byte * - 32} + * = 65, overlay + !for i, 1, 26 {!byte * + 128} + * = 97, overlay + !for i, 1, 26 {!byte * - 32} The resulting file can be used as a conversion table to convert to PetSCII (which is useless, because ACME can do so anyway. But you get the idea). @@ -358,42 +358,68 @@ Examples: ; this was taken from <6502/std.a>: } -Call: !for LABEL, TIMES { BLOCK } +Call: !for LABEL, START, END { BLOCK } Purpose: Looping assembly. The block of statements will be - parsed TIMES times. For a more flexible possibility, - have a look at "!do" below. -Parameters: LABEL: Any valid label name. The label's value will - show the number of the current loop cycle: - In the first cycle it will have the value 1, in the - last cycle it will have the value TIMES. - TIMES: Any formula the value parser accepts, but it - must be solvable even in the first pass. Negative - values are forbidden, zero causes the block to be - skipped. + parsed a fixed number of times, as specified by the + values of START and END. For a more flexible + possibility, have a look at "!do" below. +Parameters: LABEL: Any valid label name. + START: Any formula the value parser accepts, but it + must be solvable even in the first pass. LABEL will + have this value during the first loop cycle. + END: Any formula the value parser accepts, but it must + be solvable even in the first pass. LABEL will have + this value during the last loop cycle. BLOCK: A block of assembler statements. + If START or END are floats, they will be converted to + integers (never use floats for loop counters). If + START is less than or equal to END, LABEL will get + incremented at the end of each cycle; if START is + greater than END, LABEL will get decremented at the + end of each cycle. So after leaving the loop, LABEL + will have an "illegal" value (END + 1 if counting up, + END - 1 if counting down). Please note that it is impossible to change the number of loop cycles "inside" the loop by fiddling with the - counter (using the "!set" pseudo opcode): The "!for" + counter using the "!set" pseudo opcode: The "!for" routine keeps its own copy of the counter value and only sets the label value, it never reads it back. This was done to eliminate a possibility to hang ACME. -Examples: ; conversion table: integer to BCD - int2BCD !for Outer, 10 { - !for Inner, 10 { - !byte ((Outer - 1) << 4) OR (Inner - 1) +Examples: + int2BCD ; conversion table: integer to BCD + !for Outer, 0, 9 { + !for Inner, 0, 9 { + !byte (Outer << 4) OR Inner } } !fill 156, $ff ; values above 99 give 255 (invalid) - ; conversion table: BCD to integer - BCD2int !for Outer, 10 { - !for Inner, 10 { - !byte 10 * (Outer - 1) + (Inner - 1) + BCD2int ; conversion table: BCD to integer + !for Outer, 0, 9 { + !for Inner, 0, 9 { + !byte 10 * Outer + Inner } !fill 6, $ff ; invalid BCD values give 255 } !fill 96, $ff ; invalid BCD values give 255 + quickclear ; generate speedcode to clear C64 screen + lda #' ' + !for i, 0, 999 { + sta $0400 + i + } + +Miscellaneous: The old syntax ("!for LABEL, END { BLOCK }" where + START was always implied to be 1) is still fully + supported, but gives a warning to get people to change + to the new syntax. When migrating your sources, bear + in mind that it is no longer possible to skip the + block completely by specifying a loop count of zero. + Also note that with the new algorithm, LABEL has a + different value after the block than during the last + loop cycle, while the old algorithm kept that last + value. + Call: !set LABEL = VALUE Purpose: Assign given value to label even if the label already diff --git a/docs/Changes.txt b/docs/Changes.txt index fb3b8d7..4d0b7a6 100644 --- a/docs/Changes.txt +++ b/docs/Changes.txt @@ -12,6 +12,16 @@ platform used. There should be another help file in this archive outlining the platform specific changes. +---------------------------------------------------------------------- +Section: New in release 0.94.12 +---------------------------------------------------------------------- + +Finally created new "!for" syntax so counting can start at zero. The + old syntax still works, but gives a warning. See AllPOs.txt for + more info. +Added "0b" as alternative prefix for binary values. + + ---------------------------------------------------------------------- Section: New in release 0.94.11 ---------------------------------------------------------------------- diff --git a/docs/Errors.txt b/docs/Errors.txt index 5f74d3a..35f8023 100644 --- a/docs/Errors.txt +++ b/docs/Errors.txt @@ -52,9 +52,13 @@ Bug in ACME, code follows A situation has been encountered implying there is a bug in ACME. See the last section in this file. -C-style "==" comparison detected +C-style "==" comparison detected. To check for equality, use a single '=' character instead. +Found deprecated "!for" syntax. + Please update your sources to use the new "!for" syntax. See + AllPOs.txt for details. + Implicit label definition not in leftmost column. An implicit label definition has blanks before the label name. Imagine this source code: @@ -294,7 +298,8 @@ Found end-of-file instead of '}'. (because there was at least one block left open). Loop count is negative. - You used the "!for" command with a negative loop count. + You used the "!for" command with a negative loop count (getting + this error is only possible when using the now deprecated syntax). Macro already defined. Macros can only be defined once. If you define a macro twice, ACME diff --git a/docs/QuickRef.txt b/docs/QuickRef.txt index 0747793..4d21661 100644 --- a/docs/QuickRef.txt +++ b/docs/QuickRef.txt @@ -318,15 +318,16 @@ Examples Notes --------------------------------------------------------------------- 128 a decimal value, integer 128.5 a decimal value, floating point -$d011 hexadecimal values are indicated by either -0xffd2 leading "$" or leading "0x" +$d011 hexadecimal values are indicated by either a +0xffd2 leading "$" or a leading "0x". &1701 an octal value, indicated by "&" -%010010 binary values are indicated by "%". In binary values, -%....#... you can substitute the characters "0" and "1" by - "." and "#" respectively. This way the values are - much more readable, especially when building - bitmapped objects (like C64 sprites or fonts) in - your source code. +%010010 binary values are indicated by either a leading "%" +%....#... or a leading "0b". In binary values, you can +0b01100110 substitute the characters "0" and "1" by "." and + "#" respectively. This way the values are much + more readable, especially when building bitmapped + objects (like C64 sprites or fonts) in your source + code. "p" character values are indicated by double or single 'q' quotes. The actual numeric value depends on the current conversion table (none/petscii/screen), diff --git a/examples/trigono.a b/examples/trigono.a index 4e3508d..90fdce3 100644 --- a/examples/trigono.a +++ b/examples/trigono.a @@ -1,4 +1,4 @@ -;ACME 0.93 +;ACME 0.94.12 !to "trigono.o", plain * = $c000 @@ -7,10 +7,9 @@ !raw "cos[0,pi/2] scaled to 0-255 range" !align $f, 0, 0 ; make output file look better in hex editor :) - !for x, 256 { - !byte cos(float(x - 1) / 255 * PI/2) * 255 + 0.5 + !for x, 0, 255 { + !byte cos(float(x) / 255 * PI/2) * 255 + 0.5 } - ; "x-1" converts interval [1,256] to interval [0,255] ; "float()" makes sure this calculation is done in float mode now ; "/255*half_PI" converts interval [0,255] to interval [0,PI/2] ; "cos()" returns cosine. Wow. @@ -21,8 +20,8 @@ !raw "sin[-pi/2,pi/2] scaled to full range of 16b.16b fixed point" !align $f, 0, 0 - !for x, 1024 { - !32 sin(float(x - 513) / 1024 * PI) * 65536 + 0.5 + !for x, 0, 1023 { + !32 sin(float(x - 512) / 1024 * PI) * 65536 + 0.5 } ;undefined = 0.0 / 0.0 ; throws error when active diff --git a/src/acme.c b/src/acme.c index 94f289e..e489671 100644 --- a/src/acme.c +++ b/src/acme.c @@ -15,9 +15,9 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#define RELEASE "0.94.11" // update before release (FIXME) +#define RELEASE "0.94.12" // update before release (FIXME) #define CODENAME "Zarquon" // update before release -#define CHANGE_DATE "28 May" // update before release +#define CHANGE_DATE "31 May" // update before release #define CHANGE_YEAR "2014" // update before release //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME diff --git a/src/alu.c b/src/alu.c index 3d38727..6c80fcd 100644 --- a/src/alu.c +++ b/src/alu.c @@ -10,6 +10,7 @@ // so a^b^c now means a^(b^c). // 7 May 2014 C-style "==" operators are now recognized (but // give a warning). +// 31 May 2014 Added "0b" binary number prefix as alternative to "%". #include #include // only for fp support #include "platform.h" @@ -357,6 +358,46 @@ static void parse_quoted_character(char closing_quote) } +// Parse binary value. Apart from '0' and '1', it also accepts the characters +// '.' and '#', this is much more readable. The current value is stored as soon +// as a character is read that is none of those given above. +static void parse_binary_value(void) // Now GotByte = "%" or "b" +{ + intval_t value = 0; + int go_on = TRUE, // continue loop flag + flags = MVALUE_GIVEN, + digits = -1; // digit counter + + do { + digits++; + switch (GetByte()) { + case '0': + case '.': + value <<= 1; + break; + case '1': + case '#': + value = (value << 1) | 1; + break; + default: + go_on = 0; + } + } while (go_on); + // set force bits + if (digits > 8) { + if (digits > 16) { + if (value < 65536) + flags |= MVALUE_FORCE24; + } else { + if (value < 256) + flags |= MVALUE_FORCE16; + } + } + PUSH_INTOPERAND(value, flags); + // Now GotByte = non-binary char +} + + // Parse hexadecimal value. It accepts "0" to "9", "a" to "f" and "A" to "F". // Capital letters will be converted to lowercase letters using the flagtable. // The current value is stored as soon as a character is read that is none of @@ -434,10 +475,16 @@ static void parse_decimal_value(void) // Now GotByte = first digit intval_t intval = (GotByte & 15); // this works. it's ASCII. GetByte(); - // TODO - add "0b" prefix for binary values? - if ((intval == 0) && (GotByte == 'x')) { - parse_hexadecimal_value(); - return; + // check for "0b" (binary) and "0x" (hexadecimal) prefixes + if (intval == 0) { + if (GotByte == 'b') { + parse_binary_value(); + return; + } + if (GotByte == 'x') { + parse_hexadecimal_value(); + return; + } } // parse digits until no more while ((GotByte >= '0') && (GotByte <= '9')) { @@ -496,46 +543,6 @@ static void parse_program_counter(void) // Now GotByte = "*" } -// Parse binary value. Apart from '0' and '1', it also accepts the characters -// '.' and '#', this is much more readable. The current value is stored as soon -// as a character is read that is none of those given above. -static void parse_binary_value(void) // Now GotByte = "%" -{ - intval_t value = 0; - int go_on = TRUE, // continue loop flag - flags = MVALUE_GIVEN, - digits = -1; // digit counter - - do { - digits++; - switch (GetByte()) { - case '0': - case '.': - value <<= 1; - break; - case '1': - case '#': - value = (value << 1) | 1; - break; - default: - go_on = 0; - } - } while (go_on); - // set force bits - if (digits > 8) { - if (digits > 16) { - if (value < 65536) - flags |= MVALUE_FORCE24; - } else { - if (value < 256) - flags |= MVALUE_FORCE16; - } - } - PUSH_INTOPERAND(value, flags); - // Now GotByte = non-binary char -} - - // Parse function call (sin(), cos(), arctan(), ...) static void parse_function_call(void) { @@ -768,7 +775,7 @@ static void expect_dyadic_operator(void) operator = &ops_equals; // if it's "==", accept but warn if (GetByte() == '=') { - Throw_first_pass_warning("C-style \"==\" comparison detected"); + Throw_first_pass_warning("C-style \"==\" comparison detected."); goto get_byte_and_push_dyadic; } goto push_dyadic; diff --git a/src/config.h b/src/config.h index 32c2291..182f248 100644 --- a/src/config.h +++ b/src/config.h @@ -44,7 +44,7 @@ struct result_int_t { // Boolean values #ifndef FALSE #define FALSE 0 -#define TRUE 1 +#define TRUE (!FALSE) #endif diff --git a/src/flow.c b/src/flow.c index f731b37..300db08 100644 --- a/src/flow.c +++ b/src/flow.c @@ -27,9 +27,9 @@ // type definitions struct loop_condition { - int line; // original line number - int invert; // actually bool (0 for WHILE, 1 for UNTIL) - char *body; // pointer to actual expression + int line; // original line number + int invert; // actually bool (0 for WHILE, 1 for UNTIL) + char *body; // pointer to actual expression }; @@ -179,12 +179,18 @@ static enum eos PO_do(void) // Now GotByte = illegal char // looping assembly ("!for"). Has to be re-entrant. +// old syntax: !for VAR, END { BLOCK } VAR counts from 1 to END +// new syntax: !for VAR, START, END { BLOCK } VAR counts from START to END static enum eos PO_for(void) // Now GotByte = illegal char { struct input loop_input, *outer_input; struct result_t loop_counter; - intval_t maximum; + intval_t first_arg, + counter_first, + counter_last, + counter_increment; + int old_algo; // actually bool char *loop_body; // pointer to loop's body block struct label *label; zone_t zone; @@ -196,13 +202,25 @@ static enum eos PO_for(void) // Now GotByte = illegal char // Now GotByte = illegal char force_bit = Input_get_force_bit(); // skips spaces after label = Label_find(zone, force_bit); - if (Input_accept_comma() == 0) { + if (!Input_accept_comma()) { Throw_error(exception_syntax); return SKIP_REMAINDER; } - maximum = ALU_defined_int(); - if (maximum < 0) - Throw_serious_error("Loop count is negative."); + first_arg = ALU_defined_int(); + if (Input_accept_comma()) { + old_algo = FALSE; // new format - yay! + counter_first = first_arg; // use given argument + counter_last = ALU_defined_int(); // read second argument + counter_increment = (counter_last < counter_first) ? -1 : 1; + } else { + old_algo = TRUE; // old format - booo! + Throw_first_pass_warning("Found deprecated \"!for\" syntax."); + if (first_arg < 0) + Throw_serious_error("Loop count is negative."); + counter_first = 0; // CAUTION - old algo pre-increments and therefore starts with 1! + counter_last = first_arg; // use given argument + counter_increment = 1; + } if (GotByte != CHAR_SOB) Throw_serious_error(exception_no_left_brace); // remember line number of loop pseudo opcode @@ -220,16 +238,25 @@ static enum eos PO_for(void) // Now GotByte = illegal char Input_now = &loop_input; // init counter loop_counter.flags = MVALUE_DEFINED | MVALUE_EXISTS; - loop_counter.val.intval = 0; - // if count == 0, skip loop - if (maximum) { - do { - loop_counter.val.intval++; // increment counter - Label_set_value(label, &loop_counter, TRUE); - parse_ram_block(loop_start, loop_body); - } while (loop_counter.val.intval < maximum); + loop_counter.val.intval = counter_first; + Label_set_value(label, &loop_counter, TRUE); + if (old_algo) { + // old algo for old syntax: + // if count == 0, skip loop + if (counter_last) { + do { + loop_counter.val.intval += counter_increment; + Label_set_value(label, &loop_counter, TRUE); + parse_ram_block(loop_start, loop_body); + } while (loop_counter.val.intval < counter_last); + } } else { - Label_set_value(label, &loop_counter, TRUE); + // new algo for new syntax: + do { + parse_ram_block(loop_start, loop_body); + loop_counter.val.intval += counter_increment; + Label_set_value(label, &loop_counter, TRUE); + } while (loop_counter.val.intval != (counter_last + counter_increment)); } // Free memory free(loop_body);