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
* = 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

View File

@ -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
----------------------------------------------------------------------

View File

@ -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

View File

@ -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),

View File

@ -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

View File

@ -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

View File

@ -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 <stdlib.h>
#include <math.h> // 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;

View File

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

View File

@ -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);