mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-01-11 13:30:15 +00:00
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:
parent
8b2c8187a2
commit
c8ff626943
@ -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
|
||||
|
@ -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
|
||||
----------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
93
src/alu.c
93
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 <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,11 +475,17 @@ 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')) {
|
||||
// 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')) {
|
||||
intval = 10 * intval + (GotByte & 15); // ASCII, see above
|
||||
@ -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;
|
||||
|
@ -44,7 +44,7 @@ struct result_int_t {
|
||||
// Boolean values
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
|
||||
|
43
src/flow.c
43
src/flow.c
@ -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)
|
||||
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;
|
||||
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 (maximum) {
|
||||
if (counter_last) {
|
||||
do {
|
||||
loop_counter.val.intval++; // increment counter
|
||||
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 < maximum);
|
||||
} while (loop_counter.val.intval < counter_last);
|
||||
}
|
||||
} else {
|
||||
// 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user