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
This commit is contained in:
marcobaye 2014-05-31 00:46:55 +00:00
parent 8b2c8187a2
commit c8ff626943
9 changed files with 181 additions and 106 deletions

View File

@ -115,12 +115,12 @@ conversion table file, try using ACME:
!to "asc2pet.ct", plain ; no load address !to "asc2pet.ct", plain ; no load address
* = 0 ; pc = table index * = 0 ; pc = table index
; first create "as-is" table ; first create "as-is" table
!for i, 256 {!byte i - 1} !for i, 0, 255 {!byte i}
; now exchange upper and lower case characters ; now exchange upper and lower case characters
* = 65 * = 65, overlay
!for i, 91 - 65 {!byte * + 128} !for i, 1, 26 {!byte * + 128}
* = 97 * = 97, overlay
!for i, 123 - 97 {!byte * - 32} !for i, 1, 26 {!byte * - 32}
The resulting file can be used as a conversion table to convert to 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 PetSCII (which is useless, because ACME can do so anyway. But you get
the idea). 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 Purpose: Looping assembly. The block of statements will be
parsed TIMES times. For a more flexible possibility, parsed a fixed number of times, as specified by the
have a look at "!do" below. values of START and END. For a more flexible
Parameters: LABEL: Any valid label name. The label's value will possibility, have a look at "!do" below.
show the number of the current loop cycle: Parameters: LABEL: Any valid label name.
In the first cycle it will have the value 1, in the START: Any formula the value parser accepts, but it
last cycle it will have the value TIMES. must be solvable even in the first pass. LABEL will
TIMES: Any formula the value parser accepts, but it have this value during the first loop cycle.
must be solvable even in the first pass. Negative END: Any formula the value parser accepts, but it must
values are forbidden, zero causes the block to be be solvable even in the first pass. LABEL will have
skipped. this value during the last loop cycle.
BLOCK: A block of assembler statements. 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 Please note that it is impossible to change the number
of loop cycles "inside" the loop by fiddling with the 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 routine keeps its own copy of the counter value and
only sets the label value, it never reads it back. only sets the label value, it never reads it back.
This was done to eliminate a possibility to hang ACME. This was done to eliminate a possibility to hang ACME.
Examples: ; conversion table: integer to BCD Examples:
int2BCD !for Outer, 10 { int2BCD ; conversion table: integer to BCD
!for Inner, 10 { !for Outer, 0, 9 {
!byte ((Outer - 1) << 4) OR (Inner - 1) !for Inner, 0, 9 {
!byte (Outer << 4) OR Inner
} }
} }
!fill 156, $ff ; values above 99 give 255 (invalid) !fill 156, $ff ; values above 99 give 255 (invalid)
; conversion table: BCD to integer BCD2int ; conversion table: BCD to integer
BCD2int !for Outer, 10 { !for Outer, 0, 9 {
!for Inner, 10 { !for Inner, 0, 9 {
!byte 10 * (Outer - 1) + (Inner - 1) !byte 10 * Outer + Inner
} }
!fill 6, $ff ; invalid BCD values give 255 !fill 6, $ff ; invalid BCD values give 255
} }
!fill 96, $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 Call: !set LABEL = VALUE
Purpose: Assign given value to label even if the label already Purpose: Assign given value to label even if the label already

View File

@ -12,6 +12,16 @@ platform used. There should be another help file in this archive
outlining the platform specific changes. 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 Section: New in release 0.94.11
---------------------------------------------------------------------- ----------------------------------------------------------------------

View File

@ -52,9 +52,13 @@ Bug in ACME, code follows
A situation has been encountered implying there is a bug in ACME. A situation has been encountered implying there is a bug in ACME.
See the last section in this file. See the last section in this file.
C-style "==" comparison detected C-style "==" comparison detected.
To check for equality, use a single '=' character instead. 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. Implicit label definition not in leftmost column.
An implicit label definition has blanks before the label name. An implicit label definition has blanks before the label name.
Imagine this source code: Imagine this source code:
@ -294,7 +298,8 @@ Found end-of-file instead of '}'.
(because there was at least one block left open). (because there was at least one block left open).
Loop count is negative. 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. Macro already defined.
Macros can only be defined once. If you define a macro twice, ACME Macros can only be defined once. If you define a macro twice, ACME

View File

@ -318,15 +318,16 @@ Examples Notes
--------------------------------------------------------------------- ---------------------------------------------------------------------
128 a decimal value, integer 128 a decimal value, integer
128.5 a decimal value, floating point 128.5 a decimal value, floating point
$d011 hexadecimal values are indicated by either $d011 hexadecimal values are indicated by either a
0xffd2 leading "$" or leading "0x" 0xffd2 leading "$" or a leading "0x".
&1701 an octal value, indicated by "&" &1701 an octal value, indicated by "&"
%010010 binary values are indicated by "%". In binary values, %010010 binary values are indicated by either a leading "%"
%....#... you can substitute the characters "0" and "1" by %....#... or a leading "0b". In binary values, you can
"." and "#" respectively. This way the values are 0b01100110 substitute the characters "0" and "1" by "." and
much more readable, especially when building "#" respectively. This way the values are much
bitmapped objects (like C64 sprites or fonts) in more readable, especially when building bitmapped
your source code. objects (like C64 sprites or fonts) in your source
code.
"p" character values are indicated by double or single "p" character values are indicated by double or single
'q' quotes. The actual numeric value depends on the 'q' quotes. The actual numeric value depends on the
current conversion table (none/petscii/screen), current conversion table (none/petscii/screen),

View File

@ -1,4 +1,4 @@
;ACME 0.93 ;ACME 0.94.12
!to "trigono.o", plain !to "trigono.o", plain
* = $c000 * = $c000
@ -7,10 +7,9 @@
!raw "cos[0,pi/2] scaled to 0-255 range" !raw "cos[0,pi/2] scaled to 0-255 range"
!align $f, 0, 0 ; make output file look better in hex editor :) !align $f, 0, 0 ; make output file look better in hex editor :)
!for x, 256 { !for x, 0, 255 {
!byte cos(float(x - 1) / 255 * PI/2) * 255 + 0.5 !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 ; "float()" makes sure this calculation is done in float mode now
; "/255*half_PI" converts interval [0,255] to interval [0,PI/2] ; "/255*half_PI" converts interval [0,255] to interval [0,PI/2]
; "cos()" returns cosine. Wow. ; "cos()" returns cosine. Wow.
@ -21,8 +20,8 @@
!raw "sin[-pi/2,pi/2] scaled to full range of 16b.16b fixed point" !raw "sin[-pi/2,pi/2] scaled to full range of 16b.16b fixed point"
!align $f, 0, 0 !align $f, 0, 0
!for x, 1024 { !for x, 0, 1023 {
!32 sin(float(x - 513) / 1024 * PI) * 65536 + 0.5 !32 sin(float(x - 512) / 1024 * PI) * 65536 + 0.5
} }
;undefined = 0.0 / 0.0 ; throws error when active ;undefined = 0.0 / 0.0 ; throws error when active

View File

@ -15,9 +15,9 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // 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 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 CHANGE_YEAR "2014" // update before release
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME

View File

@ -10,6 +10,7 @@
// so a^b^c now means a^(b^c). // so a^b^c now means a^(b^c).
// 7 May 2014 C-style "==" operators are now recognized (but // 7 May 2014 C-style "==" operators are now recognized (but
// give a warning). // give a warning).
// 31 May 2014 Added "0b" binary number prefix as alternative to "%".
#include <stdlib.h> #include <stdlib.h>
#include <math.h> // only for fp support #include <math.h> // only for fp support
#include "platform.h" #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". // 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. // 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 // 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. intval_t intval = (GotByte & 15); // this works. it's ASCII.
GetByte(); GetByte();
// TODO - add "0b" prefix for binary values? // check for "0b" (binary) and "0x" (hexadecimal) prefixes
if ((intval == 0) && (GotByte == 'x')) { if (intval == 0) {
parse_hexadecimal_value(); if (GotByte == 'b') {
return; parse_binary_value();
return;
}
if (GotByte == 'x') {
parse_hexadecimal_value();
return;
}
} }
// parse digits until no more // parse digits until no more
while ((GotByte >= '0') && (GotByte <= '9')) { 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(), ...) // Parse function call (sin(), cos(), arctan(), ...)
static void parse_function_call(void) static void parse_function_call(void)
{ {
@ -768,7 +775,7 @@ static void expect_dyadic_operator(void)
operator = &ops_equals; operator = &ops_equals;
// if it's "==", accept but warn // if it's "==", accept but warn
if (GetByte() == '=') { 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 get_byte_and_push_dyadic;
} }
goto push_dyadic; goto push_dyadic;

View File

@ -44,7 +44,7 @@ struct result_int_t {
// Boolean values // Boolean values
#ifndef FALSE #ifndef FALSE
#define FALSE 0 #define FALSE 0
#define TRUE 1 #define TRUE (!FALSE)
#endif #endif

View File

@ -27,9 +27,9 @@
// type definitions // type definitions
struct loop_condition { struct loop_condition {
int line; // original line number int line; // original line number
int invert; // actually bool (0 for WHILE, 1 for UNTIL) int invert; // actually bool (0 for WHILE, 1 for UNTIL)
char *body; // pointer to actual expression 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. // 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 static enum eos PO_for(void) // Now GotByte = illegal char
{ {
struct input loop_input, struct input loop_input,
*outer_input; *outer_input;
struct result_t loop_counter; 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 char *loop_body; // pointer to loop's body block
struct label *label; struct label *label;
zone_t zone; zone_t zone;
@ -196,13 +202,25 @@ static enum eos PO_for(void) // Now GotByte = illegal char
// Now GotByte = illegal char // Now GotByte = illegal char
force_bit = Input_get_force_bit(); // skips spaces after force_bit = Input_get_force_bit(); // skips spaces after
label = Label_find(zone, force_bit); label = Label_find(zone, force_bit);
if (Input_accept_comma() == 0) { if (!Input_accept_comma()) {
Throw_error(exception_syntax); Throw_error(exception_syntax);
return SKIP_REMAINDER; return SKIP_REMAINDER;
} }
maximum = ALU_defined_int(); first_arg = ALU_defined_int();
if (maximum < 0) if (Input_accept_comma()) {
Throw_serious_error("Loop count is negative."); 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) if (GotByte != CHAR_SOB)
Throw_serious_error(exception_no_left_brace); Throw_serious_error(exception_no_left_brace);
// remember line number of loop pseudo opcode // 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; Input_now = &loop_input;
// init counter // init counter
loop_counter.flags = MVALUE_DEFINED | MVALUE_EXISTS; loop_counter.flags = MVALUE_DEFINED | MVALUE_EXISTS;
loop_counter.val.intval = 0; loop_counter.val.intval = counter_first;
// if count == 0, skip loop Label_set_value(label, &loop_counter, TRUE);
if (maximum) { if (old_algo) {
do { // old algo for old syntax:
loop_counter.val.intval++; // increment counter // if count == 0, skip loop
Label_set_value(label, &loop_counter, TRUE); if (counter_last) {
parse_ram_block(loop_start, loop_body); do {
} while (loop_counter.val.intval < maximum); 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 { } 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 memory
free(loop_body); free(loop_body);