Compare commits

..

22 Commits

Author SHA1 Message Date
ISSOtm
76c1995559 Fix CI 2021-04-01 11:38:07 +02:00
Rangi
ae84570f04 Revise RGBASM manual 2021-03-31 18:35:09 -04:00
Rangi
094a31ef8c Update RGBASM command-line manual 2021-03-31 18:17:18 -04:00
ISSOtm
291dcf3b6c Update RGBASM manual 2021-04-01 00:11:41 +02:00
Rangi
a890bd072b Fix "INCBIN"
Examples: (...s are optional)

ld [b @:...] = "Dockerfile"
ld [b @:...] = "Dockerfile"[451:...]
ld [b @:...] = "Dockerfile"[23:5]
ld [b @:5] = "Dockerfile"[23:...]
2021-03-31 18:06:14 -04:00
Rangi
2f6c808ccb Revise instruction reference 2021-03-31 17:59:12 -04:00
ISSOtm
e80907abd0 Update instruction reference 2021-03-31 23:26:57 +02:00
Rangi
25d39155d3 Support ld a, a±c±LOW(bc) as well as ld a, a±c±c 2021-03-30 12:36:11 -04:00
Rangi
77021d229b Support ld [c], a and ld a, [c] 2021-03-30 12:02:29 -04:00
Rangi
1b250b90b2 Implement ds <len> ==> ld [b @:<len>], ? 2021-03-30 11:54:39 -04:00
Rangi
e2b4723489 Fix lexing @ 2021-03-30 11:52:25 -04:00
Rangi
2507413162 Fix lexing a., b., etc 2021-03-30 11:41:44 -04:00
Rangi
e023a84d04 Allow 'ld a, a±c±<r8>' or 'ld a, a±<r8>±c' for adc/sbc 2021-03-30 11:27:19 -04:00
Rangi
34c127d9c3 Allow ld [b @:<len>] = "file.bin"[<ofs>:...] 2021-03-30 10:51:48 -04:00
Rangi
9a930988c2 Implement db, dw, dl, ds, and INCBIN with ld
To do: let the `b` in `ld [b @]` be optional, and allow
`ld [b @:<len>] = "file.bin"[<ofs>:...]`
2021-03-30 10:47:05 -04:00
Rangi
8c4204c542 Make 'w' and '...' tokens, and make '@' a separate token
Now '@' is valid as a relocexpr_no_str, in 'BANK(@)', and
in 'DEF(@)', but not in general T_ID or T_LABEL contexts

This will make it easier to implement INCBIN with 'ld'
2021-03-30 10:17:09 -04:00
Rangi
663c1930ec Factor out 'ld a, a+c+' and 'ld a, a-c-' prefixes
This fixes all the shift/reduce and reduce/reduce conflicts
2021-03-30 09:57:08 -04:00
Rangi
30ccf43f44 Factor out individual 'ld <r16>,' prefixes 2021-03-30 09:43:34 -04:00
Rangi
fdc17adbcb Factor out common ld a, prefix 2021-03-30 09:19:58 -04:00
Rangi
cc196954f3 Consolidate some parser rules with reg_ss and reg_r
There are now 5 shift/reduce conflicts and 3 reduce/reduce conflicts
2021-03-29 20:52:24 -04:00
Rangi
55b6cfff84 Prevent GitHub Actions from running any workflows 2021-03-29 19:50:13 -04:00
Rangi
1fc73b04eb Parse ld instructions as discussed
There are 13 shift/reduce conflicts, so some instructions
may need different formats.

This also does not yet implement `db`, `dw`, `dl`, `ds`,
or `INCBIN` using `ld`.

The `lexerState->nextToken` solution to lexing something
like "a.2" as three tokens instead of one identifier
is taken from the first commit in rgbds PR #799.
2021-03-29 19:42:18 -04:00
95 changed files with 1696 additions and 1851 deletions

View File

@@ -1,9 +0,0 @@
[*]
root = true
indent_style = tab
indent_size = tab
tab_width = 8
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf

View File

@@ -1,9 +1,10 @@
Contributing
============
RGBDS was created in the late '90s and has received contributions from several
RGBDS was created in the late 90's and has received contributions from several
developers since then. It wouldn't have been possible to get to this point
without their work, and it is always open to the contributions of other people.
without their work and, for that reason, it is always open to the contributions
of other people.
Reporting Bugs
--------------

View File

@@ -18,8 +18,6 @@ The documentation of this toolchain can be viewed online
`here <https://rgbds.gbdev.io/docs/>`__, it is generated from the man pages
found in this repository.
If you want to contribute or maintain RGBDS, and have questions regarding the code, its organisation, etc. you can find me `on GBDev <https://gbdev.io/chat>`__ or via mail at ``rgbds at eldred dot fr``.
1. Installing RGBDS
-------------------

View File

@@ -1,65 +0,0 @@
Releasing
=========
This describes for the maintainers of RGBDS how to publish a new release on
GitHub.
1. Update, commit, and push `include/version.h <include/version.h>`__ with
values for ``PACKAGE_VERSION_MAJOR``, ``PACKAGE_VERSION_MINOR``,
``PACKAGE_VERSION_PATCH``, and ``PACKAGE_VERSION_RC``. Only define
``PACKAGE_VERSION_RC`` if you are publishing a release candidate! You can
use ``git commit -m "Release <version>"`` and ``git push origin master``.
2. Create a Git tag formatted as ``v<MAJOR>.<MINOR>.<PATCH>``, or
``v<MAJOR>.<MINOR>.<PATCH>-rc<RC>`` for a release candidate. ``MAJOR``,
``MINOR``, ``PATCH``, and ``RC`` should match their values from
`include/version.h <include/version.h>`__. You can use ``git tag <tag>``.
3. Push the tag to GitHub. You can use ``git push origin <tag>``.
GitHub Actions will run the `create-release-artifacts.yaml
<.github/workflows/create-release-artifacts.yaml>`__ workflow to detect the
tag starting with "``v[0-9]``" and automatically do the following:
1. Build 32-bit and 64-bit RGBDS binaries for Windows with ``cmake``.
2. Package the binaries into zip files.
3. Package the source code into a tar.gz file with ``make dist``.
4. Create a draft GitHub release for the tag, attaching the three
packaged files. It will be a prerelease if the tag contains "``-rc``".
If an error occurred in the above steps, delete the tag and restart the
procedure. You can use ``git push --delete origin <tag>`` and
``git tag --delete <tag>``.
4. GitHub Actions will run the `create-release-docs.yml
<.github/workflows/create-release-docs.yml>`__ workflow to add the release
documentation to `rgbds-www <https://github.com/gbdev/rgbds-www>`__.
For a release candidate, which creates a prerelease, you will have to
take these steps yourself.
1. Clone `rgbds-www <https://github.com/gbdev/rgbds-www>`__. You can use
``git clone https://github.com/gbdev/rgbds-www.git``.
2. Make sure that you have installed ``groff`` and ``mandoc``. You will
need ``mandoc`` 1.14.5 or later to support ``-O toc``.
3. Run ``.github/actions/get-pages.sh -r <path/to/rgbds-www> <tag>``. This
will render the RGBDS documentation as HTML and PDF and copy it to
``rgbds-www``.
If you do not have ``groff`` installed, you can change
``groff -Tpdf -mdoc -wall`` to ``mandoc -Tpdf -I os=Linux`` in
`.github/actions/get-pages.sh <.github/actions/get-pages.sh>`__ and it
will suffice.
4. Commit and push the documentation. You can use ``git commit -m
"Create RGBDS <tag> documentation"`` and ``git push origin master``
(within the ``rgbds-www`` directory, not RGBDS).
5. Write a changelog in the GitHub draft release.
6. Click the "Publish release" button to publish it!

View File

@@ -28,9 +28,9 @@ struct FormatSpec {
bool prefix;
bool alignLeft;
bool padZero;
size_t width;
uint8_t width;
bool hasFrac;
size_t fracWidth;
uint8_t fracWidth;
int type;
bool valid;
};

View File

@@ -11,8 +11,8 @@
#include <stdint.h>
char const *printChar(int c);
uint32_t calchash(const char *s);
char const *print(int c);
/*
* @return The number of bytes read, or 0 if invalid data was found
*/

View File

@@ -15,7 +15,6 @@ extern unsigned int nbErrors;
enum WarningID {
WARNING_ASSERT, /* Assertions */
WARNING_BACKWARDS_FOR, /* `for` loop with backwards range */
WARNING_BUILTIN_ARG, /* Invalid args to builtins */
WARNING_CHARMAP_REDEF, /* Charmap entry re-definition */
WARNING_DIV, /* Division undefined behavior */

View File

@@ -29,9 +29,19 @@ typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
* @param map The HashMap to add the element to
* @param key The key with which the element will be stored and retrieved
* @param element The element to add
* @return A pointer to the pointer to the element.
* @return True if a collision occurred (for statistics)
*/
void **hash_AddElement(HashMap map, char const *key, void *element);
bool hash_AddElement(HashMap map, char const *key, void *element);
/**
* Replaces an element with an already-present key in a hashmap.
* @warning Inserting a NULL will make `hash_GetElement`'s return ambiguous!
* @param map The HashMap to replace the element in
* @param key The key with which the element will be stored and retrieved
* @param element The element to replace
* @return True if the element was found and replaced
*/
bool hash_ReplaceElement(HashMap const map, char const *key, void *element);
/**
* Removes an element from a hashmap.
@@ -41,14 +51,6 @@ void **hash_AddElement(HashMap map, char const *key, void *element);
*/
bool hash_RemoveElement(HashMap map, char const *key);
/**
* Finds an element in a hashmap, and returns a pointer to its value field.
* @param map The map to consider the elements of
* @param key The key to search an element for
* @return A pointer to the pointer to the element, or NULL if not found.
*/
void **hash_GetNode(HashMap const map, char const *key);
/**
* Finds an element in a hashmap.
* @param map The map to consider the elements of

View File

@@ -12,6 +12,7 @@
#define PACKAGE_VERSION_MAJOR 0
#define PACKAGE_VERSION_MINOR 5
#define PACKAGE_VERSION_PATCH 0
#define PACKAGE_VERSION_RC 2
const char *get_package_version_string(void);

View File

@@ -44,35 +44,32 @@ struct Charmap {
static HashMap charmaps;
/*
* Store pointers to hashmap nodes, so that there is only one pointer to the memory block
* that gets reallocated.
*/
static struct Charmap **currentCharmap;
static struct Charmap *currentCharmap;
struct CharmapStackEntry {
struct Charmap **charmap;
struct Charmap *charmap;
struct CharmapStackEntry *next;
};
struct CharmapStackEntry *charmapStack;
static struct Charmap *charmap_Get(const char *name)
static inline struct Charmap *charmap_Get(const char *name)
{
return hash_GetElement(charmaps, name);
}
static void resizeCharmap(struct Charmap **map, size_t capacity)
static inline struct Charmap *resizeCharmap(struct Charmap *map, size_t capacity)
{
*map = realloc(*map, sizeof(**map) + sizeof(*(*map)->nodes) * capacity);
struct Charmap *new = realloc(map, sizeof(*map) + sizeof(*map->nodes) * capacity);
if (!*map)
if (!new)
fatalerror("Failed to %s charmap: %s\n",
*map ? "create" : "resize", strerror(errno));
(**map).capacity = capacity;
map ? "create" : "resize", strerror(errno));
new->capacity = capacity;
return new;
}
static void initNode(struct Charnode *node)
static inline void initNode(struct Charnode *node)
{
node->isTerminal = false;
memset(node->next, 0, sizeof(node->next));
@@ -98,18 +95,19 @@ struct Charmap *charmap_New(const char *name, const char *baseName)
/* Init the new charmap's fields */
if (base) {
resizeCharmap(&charmap, base->capacity);
charmap = resizeCharmap(NULL, base->capacity);
charmap->usedNodes = base->usedNodes;
memcpy(charmap->nodes, base->nodes, sizeof(base->nodes[0]) * charmap->usedNodes);
} else {
resizeCharmap(&charmap, INITIAL_CAPACITY);
charmap = resizeCharmap(NULL, INITIAL_CAPACITY);
charmap->usedNodes = 1;
initNode(&charmap->nodes[0]); /* Init the root node */
}
charmap->name = strdup(name);
currentCharmap = (struct Charmap **)hash_AddElement(charmaps, charmap->name, charmap);
hash_AddElement(charmaps, charmap->name, charmap);
currentCharmap = charmap;
return charmap;
}
@@ -122,7 +120,7 @@ void charmap_Delete(struct Charmap *charmap)
void charmap_Set(const char *name)
{
struct Charmap **charmap = (struct Charmap **)hash_GetNode(charmaps, name);
struct Charmap *charmap = charmap_Get(name);
if (charmap == NULL)
error("Charmap '%s' doesn't exist\n", name);
@@ -160,26 +158,25 @@ void charmap_Pop(void)
void charmap_Add(char *mapping, uint8_t value)
{
struct Charmap *charmap = *currentCharmap;
struct Charnode *node = &charmap->nodes[0];
struct Charnode *node = &currentCharmap->nodes[0];
for (uint8_t c; *mapping; mapping++) {
c = *mapping - 1;
if (node->next[c]) {
node = &charmap->nodes[node->next[c]];
node = &currentCharmap->nodes[node->next[c]];
} else {
/* Register next available node */
node->next[c] = charmap->usedNodes;
node->next[c] = currentCharmap->usedNodes;
/* If no more nodes are available, get new ones */
if (charmap->usedNodes == charmap->capacity) {
charmap->capacity *= 2;
resizeCharmap(currentCharmap, charmap->capacity);
charmap = *currentCharmap;
if (currentCharmap->usedNodes == currentCharmap->capacity) {
currentCharmap->capacity *= 2;
currentCharmap = resizeCharmap(currentCharmap, currentCharmap->capacity);
hash_ReplaceElement(charmaps, currentCharmap->name, currentCharmap);
}
/* Switch to and init new node */
node = &charmap->nodes[charmap->usedNodes++];
node = &currentCharmap->nodes[currentCharmap->usedNodes++];
initNode(node);
}
}
@@ -200,8 +197,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
* If no match, read a UTF-8 codepoint and output that.
*/
size_t outputLen = 0;
struct Charmap const *charmap = *currentCharmap;
struct Charnode const *node = &charmap->nodes[0];
struct Charnode const *node = &currentCharmap->nodes[0];
struct Charnode const *match = NULL;
size_t rewindDistance = 0;
@@ -213,7 +209,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
input++; /* Consume that char */
rewindDistance++;
node = &charmap->nodes[node->next[c]];
node = &currentCharmap->nodes[node->next[c]];
if (node->isTerminal) {
match = node;
rewindDistance = 0; /* Rewind from after the match */
@@ -222,7 +218,7 @@ size_t charmap_Convert(char const *input, uint8_t *output)
} else {
input -= rewindDistance; /* Rewind */
rewindDistance = 0;
node = &charmap->nodes[0];
node = &currentCharmap->nodes[0];
if (match) { /* Arrived at a dead end with a match found */
*output++ = match->value;

View File

@@ -6,7 +6,6 @@
* SPDX-License-Identifier: MIT
*/
#include <assert.h>
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
@@ -149,24 +148,20 @@ void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, cha
size_t len = strlen(value);
size_t totalLen = fmt->width > len ? fmt->width : len;
if (totalLen > bufLen - 1) { /* bufLen includes terminator */
if (totalLen + 1 > bufLen) /* bufLen includes terminator */
error("Formatted string value too long\n");
totalLen = bufLen - 1;
if (len > totalLen)
len = totalLen;
}
assert(len < bufLen && totalLen < bufLen && len <= totalLen);
size_t padLen = totalLen - len;
size_t padLen = fmt->width > len ? fmt->width - len : 0;
if (fmt->alignLeft) {
memcpy(buf, value, len);
for (size_t i = len; i < totalLen; i++)
buf[i] = ' ';
strncpy(buf, value, len < bufLen ? len : bufLen);
for (size_t i = 0; i < totalLen && len + i < bufLen; i++)
buf[len + i] = ' ';
} else {
for (size_t i = 0; i < padLen; i++)
for (size_t i = 0; i < padLen && i < bufLen; i++)
buf[i] = ' ';
memcpy(buf + padLen, value, len);
if (bufLen > padLen)
strncpy(buf + padLen, value, bufLen - padLen - 1);
}
buf[totalLen] = '\0';
@@ -226,18 +221,12 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
/* Special case for fixed-point */
/* Default fractional width (C's is 6 for "%f"; here 5 is enough) */
size_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
uint8_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
if (fracWidth) {
if (fracWidth > 255) {
error("Fractional width %zu too long, limiting to 255\n",
fracWidth);
fracWidth = 255;
}
char spec[16]; /* Max "%" + 5-char PRIu32 + ".%0255.f" + terminator */
snprintf(spec, sizeof(spec), "%%" PRIu32 ".%%0%zu.f", fracWidth);
snprintf(spec, sizeof(spec), "%%" PRIu32 ".%%0%d.f", fracWidth);
snprintf(valueBuf, sizeof(valueBuf), spec, value >> 16,
(value % 65536) / 65536.0 * pow(10, fracWidth) + 0.5);
} else {
@@ -255,49 +244,55 @@ void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uin
}
size_t len = strlen(valueBuf);
size_t numLen = !!sign + !!prefix + len;
size_t numLen = len;
if (sign)
numLen++;
if (prefix)
numLen++;
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
if (totalLen > bufLen - 1) { /* bufLen includes terminator */
if (totalLen + 1 > bufLen) /* bufLen includes terminator */
error("Formatted numeric value too long\n");
totalLen = bufLen - 1;
if (numLen > totalLen) {
len -= numLen - totalLen;
numLen = totalLen;
}
}
assert(numLen < bufLen && totalLen < bufLen && numLen <= totalLen && len <= numLen);
size_t padLen = totalLen - numLen;
size_t pos = 0;
size_t padLen = fmt->width > numLen ? fmt->width - numLen : 0;
if (fmt->alignLeft) {
if (sign)
size_t pos = 0;
if (sign && pos < bufLen)
buf[pos++] = sign;
if (prefix)
if (prefix && pos < bufLen)
buf[pos++] = prefix;
memcpy(buf + pos, valueBuf, len);
for (size_t i = pos + len; i < totalLen; i++)
buf[i] = ' ';
strcpy(buf + pos, valueBuf);
pos += len;
for (size_t i = 0; i < totalLen && pos + i < bufLen; i++)
buf[pos + i] = ' ';
} else {
size_t pos = 0;
if (fmt->padZero) {
/* sign, then prefix, then zero padding */
if (sign)
if (sign && pos < bufLen)
buf[pos++] = sign;
if (prefix)
if (prefix && pos < bufLen)
buf[pos++] = prefix;
for (size_t i = 0; i < padLen; i++)
for (size_t i = 0; i < padLen && pos < bufLen; i++)
buf[pos++] = '0';
} else {
/* space padding, then sign, then prefix */
for (size_t i = 0; i < padLen; i++)
for (size_t i = 0; i < padLen && pos < bufLen; i++)
buf[pos++] = ' ';
if (sign)
if (sign && pos < bufLen)
buf[pos++] = sign;
if (prefix)
if (prefix && pos < bufLen)
buf[pos++] = prefix;
}
memcpy(buf + pos, valueBuf, len);
if (bufLen > pos)
strcpy(buf + pos, valueBuf);
}
buf[totalLen] = '\0';

View File

@@ -191,11 +191,6 @@ bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
break;
}
len = sprintf(*fullPath, "%s%s", incPath, path);
if (len < 0) {
error("sprintf error during include path search: %s\n",
strerror(errno));
break;
}
}
if (isPathValid(*fullPath)) {
@@ -492,10 +487,6 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
else if (step == 0)
error("FOR cannot have a step value of 0\n");
if ((step > 0 && start > stop) || (step < 0 && start < stop))
warning(WARNING_BACKWARDS_FOR, "FOR goes backwards from %d to %d by %d\n",
start, stop, step);
if (count == 0)
return;
if (!newReptContext(reptLineNo, body, size))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -83,7 +83,7 @@ Add an include path.
Disable the optimization that turns loads of the form
.Ic LD [$FF00+n8],A
into the opcode
.Ic LDH [$FF00+n8],A
.Ic LD [H $FF00+n8],A
in order to have full control of the result in the final ROM.
.It Fl M Ar depend_file , Fl Fl dependfile Ar depend_file
Print
@@ -189,7 +189,7 @@ Ignoring the
prefix, entries are listed alphabetically.
.Bl -tag -width Ds
.It Fl Wno-assert
Warn when
Warns when
.Ic WARN Ns No -type
assertions fail. (See
.Dq Aborting the assembly process
@@ -197,12 +197,6 @@ in
.Xr rgbasm 5
for
.Ic ASSERT ) .
.It Fl Wbackwards-for
Warn when
.Ic FOR
loops have their start and stop values switched according to the step value.
This warning is enabled by
.Fl Wall .
.It Fl Wbuiltin-args
Warn about incorrect arguments to built-in functions, such as
.Fn STRSUB
@@ -245,12 +239,12 @@ constant or
directive are encountered.
.It Fl Wshift
Warn when shifting right a negative value.
Use a division by 2**N instead.
Use a division by 2^N instead.
.It Fl Wshift-amount
Warn when a shift's operand is negative or greater than 32.
.It Fl Wno-truncation
Warn when an implicit truncation (for example,
.Ic db )
.Ic LD [B @] )
loses some bits.
.It Fl Wno-user
Warn when the

View File

@@ -63,9 +63,9 @@ X = /* the value of x
Sometimes lines can be too long and it may be necessary to split them.
To do so, put a backslash at the end of the line:
.Bd -literal -offset indent
DB 1, 2, 3,\ \[rs]
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
7, 8, 9
LD [B @:...], 1, 2, 3,\ \[rs]
4, 5, 6,\ \[rs]\ ;\ Put it before any comments
7, 8, 9
.Ed
.Pp
This works anywhere in the code except inside of strings.
@@ -73,8 +73,8 @@ To split strings it is needed to use
.Fn STRCAT
like this:
.Bd -literal -offset indent
db STRCAT("Hello ",\ \[rs]
"world!")
LD [B @:], STRCAT("Hello ",\ \[rs]
"world!")
.Ed
.Sh EXPRESSIONS
An expression can be composed of many things.
@@ -226,7 +226,7 @@ For example:
; (shifted and scaled from the range [-1.0, 1.0])
ANGLE = 0.0
REPT 256
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
ld [b @], (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
ENDR
.Ed
@@ -337,7 +337,7 @@ followed by one or more
\[en]
.Ql 9 .
If specified, prints this many digits of a fixed-point fraction.
Defaults to 5 digits, maximum 255 digits.
Defaults to 5 digits.
.It Ql <type> Ta Specifies the type of value.
.El
.Pp
@@ -417,9 +417,9 @@ CHARMAP "&iacute", 20
CHARMAP "A", 128
.Ed
This would result in
.Ql db \(dqAmen<LF>\(dq
.Ql ld [b @:...], \(dqAmen<LF>\(dq
being equivalent to
.Ql db 128, 109, 101, 110, 10 .
.Ql ld [b @:...], 128, 109, 101, 110, 10 .
.Pp
Any characters in a string without defined mappings will be copied directly, using the source file's encoding of characters to bytes.
.Pp
@@ -574,15 +574,15 @@ While
will automatically optimize
.Ic ld
instructions to the smaller and faster
.Ic ldh
.Ic ld\ h
(see
.Xr gbz80 7 )
whenever possible, it is generally unable to do so when a label is involved.
Using the
.Ic ldh
.Ic ld\ h
instruction directly is recommended.
This forces the assembler to emit a
.Ic ldh
.Ic ld\ h
instruction and the linker to check if the value is in the correct range.
.El
.Pp
@@ -699,11 +699,11 @@ CopyCode:
ld c, RAMLocation.end - RAMLocation
\&.loop
ld a, [de]
inc de
ld de+
ld [hli], a
dec c
jr nz, .loop
ret
ld c-
ld nz pc, b .loop
ld pc,[sp++]
RAMCode:
LOAD "RAM code", WRAM0
@@ -713,13 +713,13 @@ RAMLocation:
\&.copy
ld a, [hli]
ld [de], a
inc de
and a
jr nz, .copy
ret
ld de+
ld a,a&a
ld nz pc, b .copy
ld pc,[sp++]
\&.string
db "Hello World!", 0
ld [b @:...], "Hello World!", 0
\&.end
ENDL
.Ed
@@ -929,14 +929,14 @@ references the one before the expression;
and so on.
.Bd -literal -offset indent
ld hl, :++
: ld a, [hli] ; referenced by "jr nz"
ldh [c], a
dec c
jr nz, :-
ret
: ld a, [hli] ; referenced by "ld nz pc"
ld [h c], a
ld c-
ld nz pc,b :-
ld pc,[sp++]
: ; referenced by "ld hl"
dw $7FFF, $1061, $03E0, $58A5
ld [w @:], $7FFF, $1061, $03E0, $58A5
.Ed
.Pp
A label's location (and thus value) is usually not determined until the linking stage, so labels usually cannot be used as constants.
@@ -1036,18 +1036,18 @@ DEF COUNTREG EQUS "[hl+]"
ld a,COUNTREG
DEF PLAYER_NAME EQUS "\[rs]"John\[rs]""
db PLAYER_NAME
ld [b @:], PLAYER_NAME
.Ed
.Pp
This will be interpreted as:
.Bd -literal -offset indent
ld a,[hl+]
db "John"
ld [b @:], "John"
.Ed
.Pp
String equates can also be used to define small one-line macros:
.Bd -literal -offset indent
DEF pusha EQUS "push af\[rs]npush bc\[rs]npush de\[rs]npush hl\[rs]n"
DEF ld_de_hl EQUS "ld d,h\[rs]n ld e,l\[rs]n"
.Ed
.Pp
Note that colons
@@ -1135,7 +1135,7 @@ constructs.
.Bd -literal -offset indent
MACRO MyMacro
ld a, 80
call MyFunc
ld[--sp],pc, MyFunc
ENDM
.Ed
.Pp
@@ -1208,9 +1208,9 @@ ExportedLabelB2:
.Ql c.asm :
.Bd -literal -compact
SECTION "C", ROM0[0]
dw LabelA
dw ExportedLabelB1
dw ExportedLabelB2
ld [w @], LabelA
ld [w @], ExportedLabelB1
ld [w @], ExportedLabelB2
.Ed
.Pp
Then
@@ -1272,7 +1272,6 @@ The following symbols are defined by the assembler:
.It Dv __RGBDS_MINOR__ Ta Ic EQU Ta Minor version number of RGBDS
.It Dv __RGBDS_PATCH__ Ta Ic EQU Ta Patch version number of RGBDS
.It Dv __RGBDS_RC__ Ta Ic EQU Ta Release candidate ID of RGBDS, not defined for final releases
.It Dv __RGBDS_VERSION__ Ta Ic EQUS Ta Version of RGBDS, as printed by Ql rgbasm --version
.El
.Pp
The current time values will be taken from the
@@ -1282,18 +1281,20 @@ Refer to the spec at
.Lk https://reproducible-builds.org/docs/source-date-epoch/ .
.Sh DEFINING DATA
.Ss Declaring variables in a RAM section
.Ic DS
.Ic LD [B @:<len>]
allocates a number of empty bytes.
This is the preferred method of allocating space in a RAM section.
You can also use
.Ic DB , DW
.Ic LD [B @] , LD [W @]
and
.Ic DL
without any arguments instead (see
.Ic LD [L @]
with
.Ql \&?
instead (see
.Sx Defining constant data
below).
.Bd -literal -offset indent
DS 42 ;\ Allocates 42 bytes
LD [B @:42], ? ;\ Allocates 42 bytes
.Ed
.Pp
Empty space in RAM sections will not be initialized.
@@ -1302,17 +1303,24 @@ In ROM sections, it will be filled with the value passed to the
command-line option, except when using overlays with
.Fl O .
.Ss Defining constant data
.Ic DB
.Ic LD [B @]
defines a list of bytes that will be stored in the final image.
Ideal for tables and text.
.Bd -literal -offset indent
DB 1,2,3,4,"This is a string"
LD [B @:...], 1,2,3,4,"This is a string"
.Ed
.Pp
Python slice syntax is used: for a single byte, close the brackets immediately after
.Ql @ ;
if more than one entry follows, a colon must be added after the
.Ql @ ,
optionally followed by an ellipsis
.Ql ... .
.Pp
Alternatively, you can use
.Ic DW
.Ic LD [W @]
to store a list of words (16-bit) or
.Ic DL
.Ic LD [L @]
to store a list of double-words/longs (32-bit).
.Pp
Strings are handled a little specially: they first undergo charmap conversion (see
@@ -1320,36 +1328,42 @@ Strings are handled a little specially: they first undergo charmap conversion (s
then each resulting character is output individually.
For example, under the default charmap, the following two lines are identical:
.Bd -literal -offset indent
DW "Hello!"
DW "H", "e", "l", "l", "o", "!"
LD [W @:], "Hello!"
LD [W @:], "H", "e", "l", "l", "o", "!"
.Ed
.Pp
Note that strings require a colon after the
.Ql @
in the directive.
.Pp
If you do not want this special handling, enclose the string in parentheses.
.Pp
.Ic DS
.Ic LD [B @:<len>]
can also be used to fill a region of memory with some repeated values.
For example:
.Bd -literal -offset indent
; outputs 3 bytes: $AA, $AA, $AA
DS 3, $AA
LD [B @:3], $AA
; outputs 7 bytes: $BB, $CC, $BB, $CC, $BB, $CC, $BB
DS 7, $BB, $CC
LD [B @:7], $BB, $CC
.Ed
.Pp
You can also use
.Ic DB , DW
.Ic LD [B @] , LD [W @]
and
.Ic DL
without arguments.
.Ic LD [L @]
with
.Ql \&?
as its sole argument (in which case neither the colon nor an ellipsis may be present).
This works exactly like
.Ic DS 1 , DS 2
.Ic LD [B @:1] , LD [B @:2]
and
.Ic DS 4
.Ic LD [B @:4]
respectively.
Consequently, no-argument
.Ic DB , DW
Consequently, these forms of
.Ic LD [B @] , LD [W @]
and
.Ic DL
.Ic LD [L @]
can be used in a
.Ic WRAM0
/
@@ -1364,23 +1378,25 @@ section.
.Ss Including binary files
You probably have some graphics, level data, etc. you'd like to include.
Use
.Ic INCBIN
.Ic LD [B @:...] =
to include a raw binary file as it is.
.Pq The ellipsis are optional.
If the file isn't found in the current directory, the include-path list passed to
.Xr rgbasm 1
(see the
.Fl i
option) on the command line will be searched.
.Bd -literal -offset indent
INCBIN "titlepic.bin"
INCBIN "sprites/hero.bin"
LD [B @:] = "titlepic.bin"
LD [B @:...] = "sprites/hero.bin"
.Ed
.Pp
You can also include only part of a file with
.Ic INCBIN .
The example below includes 256 bytes from data.bin, starting from byte 78.
.Ic LD [B @:] .
The examples below include 256 bytes from data.bin, starting from byte 78.
.Bd -literal -offset indent
INCBIN "data.bin",78,256
LD [B @:] = "data.bin"[78:256]
LD [B @:256] = "data.bin"[78:]
.Ed
.Pp
The length argument is optional.
@@ -1400,19 +1416,19 @@ separates each block of allocations, and you may use it as many times within a u
; Let's say PC = $C0DE here
UNION
; Here, PC = $C0DE
Name: ds 8
Name: ld [b @:8], ?
; PC = $C0E6
Nickname: ds 8
Nickname: ld [b @:8], ?
; PC = $C0EE
NEXTU
; PC is back to $C0DE
Health: dw
Health: ld [w @], ?
; PC = $C0E0
Something: ds 6
Something: ld [b @:6], ?
; And so on
Lives: db
Lives: ld [b @], ?
NEXTU
VideoBuffer: ds 19
VideoBuffer: ld [b @:19], ?
ENDU
.Ed
.Pp
@@ -1432,17 +1448,17 @@ The size of this union is 19 bytes, as this is the size of the largest block (th
Nesting unions is possible, with each inner union's size being considered as described above.
.Pp
Unions may be used in any section, but inside them may only be
.Ic DS -
.Ic LD\ [B\ @],\ ? Ns - Ns
like commands (see
.Sx Declaring variables in a RAM section ) .
.Sh THE MACRO LANGUAGE
.Ss Invoking macros
You execute the macro by inserting its name.
.Bd -literal -offset indent
add a,b
ld a,a+b
ld sp,hl
MyMacro ;\ This will be expanded
sub a,87
ld a,a-87
.Ed
.Pp
It's valid to call a macro from a macro (yes, even the same one).
@@ -1459,10 +1475,10 @@ it will insert the macro definition (the code enclosed in
Suppose your macro contains a loop.
.Bd -literal -offset indent
MACRO LoopyMacro
xor a,a
ld a,a^a
\&.loop ld [hl+],a
dec c
jr nz,.loop
ld c-
ld nz pc,b .loop
ENDM
.Ed
.Pp
@@ -1477,10 +1493,10 @@ also works in
blocks.
.Bd -literal -offset indent
MACRO LoopyMacro
xor a,a
ld a,a^a
\&.loop\[rs]@ ld [hl+],a
dec c
jr nz,.loop\[rs]@
ld c-
ld nz pc,b .loop\[rs]@
ENDM
.Ed
.Pp
@@ -1508,10 +1524,10 @@ being the first argument specified on the macro invocation.
MACRO LoopyMacro
ld hl,\[rs]1
ld c,\[rs]2
xor a,a
ld a,a^a
\&.loop\[rs]@ ld [hl+],a
dec c
jr nz,.loop\[rs]@
ld c-
ld nz pc,b .loop\[rs]@
ENDM
.Ed
.Pp
@@ -1623,7 +1639,7 @@ The following example will assemble
four times:
.Bd -literal -offset indent
REPT 4
add a,c
ld a,a+c
ENDR
.Ed
.Pp
@@ -1635,7 +1651,7 @@ to generate tables on the fly:
; (shifted and scaled from the range [-1.0, 1.0])
ANGLE = 0.0
REPT 256
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
ld [b @], (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries
ENDR
.Ed
@@ -1659,21 +1675,21 @@ String equates are not expanded within the symbol name.
For example, this code will produce a table of squared values from 0 to 255:
.Bd -literal -offset indent
FOR N, 256
dw N * N
ld [w @], N * N
ENDR
.Ed
.Pp
It acts just as if you had done:
.Bd -literal -offset ident
N = 0
dw N * N
ld [w @], N * N
N = 1
dw N * N
ld [w @], N * N
N = 2
dw N * N
ld [w @], N * N
; ...
N = 255
dw N * N
ld [w @], N * N
N = 256
.Ed
.Pp
@@ -1764,18 +1780,18 @@ and
Syntax examples are given below:
.Bd -literal -offset indent
Function:
xor a
ld a,a^a
ASSERT LOW(Variable) == 0
ld h, HIGH(Variable)
ld l, a
ld a, [hli]
; You can also indent this!
ASSERT BANK(OtherFunction) == BANK(Function)
call OtherFunction
ld [--sp], pc,OtherFunction
; Lowercase also works
assert Variable + 1 == OtherVariable
ld c, [hl]
ret
ld pc,[sp++]
\&.end
; If you specify one, a message will be printed
STATIC_ASSERT .end - Function < 256, "Function is too large!"
@@ -1884,9 +1900,9 @@ takes a comma-separated list of options as its argument:
.Bd -literal -offset indent
PUSHO
OPT g.oOX ;Set the GB graphics constants to use these characters
DW `..ooOOXX
LD [W @], `..ooOOXX
POPO
DW `00112233
LD [W @], `00112233
.Ed
.Pp
The options that OPT can modify are currently:

View File

@@ -41,7 +41,7 @@ struct UnionStackEntry {
/*
* A quick check to see if we have an initialized section
*/
static void checksection(void)
static inline void checksection(void)
{
if (pCurrentSection == NULL)
fatalerror("Code generation before SECTION directive\n");
@@ -51,7 +51,7 @@ static void checksection(void)
* A quick check to see if we have an initialized section that can contain
* this much initialized data
*/
static void checkcodesection(void)
static inline void checkcodesection(void)
{
checksection();
@@ -60,7 +60,7 @@ static void checkcodesection(void)
pCurrentSection->name);
}
static void checkSectionSize(struct Section const *sect, uint32_t size)
static inline void checkSectionSize(struct Section const *sect, uint32_t size)
{
uint32_t maxSize = maxsize[sect->type];
@@ -72,7 +72,7 @@ static void checkSectionSize(struct Section const *sect, uint32_t size)
/*
* Check if the section has grown too much.
*/
static void reserveSpace(uint32_t delta_size)
static inline void reserveSpace(uint32_t delta_size)
{
/*
* This check is here to trap broken code that generates sections that
@@ -339,8 +339,6 @@ static struct Section *getSection(char const *name, enum SectionType type, uint3
} else if (startaddr[type] & mask) {
error("Section \"%s\"'s alignment cannot be attained in %s\n",
name, typeNames[type]);
alignment = 0; /* Ignore it if it's unattainable */
org = 0;
} else if (alignment == 16) {
// Treat an alignment of 16 as being fixed at address 0
alignment = 0;
@@ -474,7 +472,7 @@ void sect_AlignPC(uint8_t alignment, uint16_t offset)
}
}
static void growSection(uint32_t growth)
static inline void growSection(uint32_t growth)
{
curOffset += growth;
if (curOffset + loadOffset > pCurrentSection->size)
@@ -483,19 +481,19 @@ static void growSection(uint32_t growth)
currentLoadSection->size = curOffset;
}
static void writebyte(uint8_t byte)
static inline void writebyte(uint8_t byte)
{
pCurrentSection->data[sect_GetOutputOffset()] = byte;
growSection(1);
}
static void writeword(uint16_t b)
static inline void writeword(uint16_t b)
{
writebyte(b & 0xFF);
writebyte(b >> 8);
}
static void writelong(uint32_t b)
static inline void writelong(uint32_t b)
{
writebyte(b & 0xFF);
writebyte(b >> 8);
@@ -503,7 +501,8 @@ static void writelong(uint32_t b)
writebyte(b >> 24);
}
static void createPatch(enum PatchType type, struct Expression const *expr, uint32_t pcShift)
static inline void createPatch(enum PatchType type, struct Expression const *expr,
uint32_t pcShift)
{
out_CreatePatch(type, expr, sect_GetOutputOffset(), pcShift);
}
@@ -780,7 +779,8 @@ void out_BinaryFile(char const *s, int32_t startPos)
if (startPos > fsize) {
error("Specified start position is greater than length of file\n");
goto cleanup;
fclose(f);
return;
}
fseek(f, startPos, SEEK_SET);
@@ -803,7 +803,6 @@ void out_BinaryFile(char const *s, int32_t startPos)
if (ferror(f))
error("Error reading INCBIN file '%s': %s\n", s, strerror(errno));
cleanup:
fclose(f);
}
@@ -827,16 +826,16 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
if (fstk_FindFile(s, &fullPath, &size))
f = fopen(fullPath, "rb");
free(fullPath);
if (!f) {
free(fullPath);
if (oGeneratedMissingIncludes) {
if (verbose)
printf("Aborting (-MG) on INCBIN file '%s' (%s)\n", s, strerror(errno));
oFailedOnMissingInclude = true;
} else {
error("Error opening INCBIN file '%s': %s\n", s, strerror(errno));
return;
}
error("Error opening INCBIN file '%s': %s\n", s, strerror(errno));
return;
}
@@ -850,13 +849,13 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
if (start_pos > fsize) {
error("Specified start position is greater than length of file\n");
goto cleanup;
return;
}
if ((start_pos + length) > fsize) {
error("Specified range in INCBIN is out of bounds (%" PRIu32 " + %" PRIu32
" > %" PRIu32 ")\n", start_pos, length, fsize);
goto cleanup;
return;
}
fseek(f, start_pos, SEEK_SET);
@@ -884,8 +883,8 @@ void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)
}
}
cleanup:
fclose(f);
free(fullPath);
}
/*

View File

@@ -43,6 +43,12 @@ static char savedTIME[256];
static char savedDATE[256];
static char savedTIMESTAMP_ISO8601_LOCAL[256];
static char savedTIMESTAMP_ISO8601_UTC[256];
static char savedDAY[3];
static char savedMONTH[3];
static char savedYEAR[20];
static char savedHOUR[3];
static char savedMINUTE[3];
static char savedSECOND[3];
static bool exportall;
bool sym_IsPC(struct Symbol const *sym)
@@ -269,7 +275,7 @@ struct Symbol const *sym_GetPC(void)
return PCSymbol;
}
static bool isReferenced(struct Symbol const *sym)
static inline bool isReferenced(struct Symbol const *sym)
{
return sym->ID != (uint32_t)-1;
}
@@ -373,7 +379,6 @@ static struct Symbol *createNonrelocSymbol(char const *symbolName, bool numeric)
error("'%s' already defined at ", symbolName);
dumpFilename(symbol);
putc('\n', stderr);
return NULL; // Don't allow overriding the symbol, that'd be bad!
} else if (!numeric) {
// The symbol has already been referenced, but it's not allowed
error("'%s' already referenced at ", symbolName);
@@ -434,10 +439,6 @@ struct Symbol *sym_RedefString(char const *symName, char const *value)
error("'%s' already defined as non-EQUS at ", symName);
dumpFilename(sym);
putc('\n', stderr);
return NULL;
} else if (sym->isBuiltin) {
error("Built-in symbol '%s' cannot be redefined\n", symName);
return NULL;
}
/*
@@ -680,7 +681,18 @@ void sym_SetExportAll(bool set)
exportall = set;
}
static struct Symbol *createBuiltinSymbol(char const *name)
/**
* Returns a pointer to the first non-zero character in a string
* Non-'0', not non-'\0'.
*/
static inline char const *removeLeadingZeros(char const *ptr)
{
while (*ptr == '0')
ptr++;
return ptr;
}
static inline struct Symbol *createBuiltinSymbol(char const *name)
{
struct Symbol *sym = createsymbol(name);
@@ -710,18 +722,13 @@ void sym_Init(time_t now)
__LINE__Symbol->numCallback = Callback__LINE__;
__FILE__Symbol->type = SYM_EQUS;
__FILE__Symbol->strCallback = Callback__FILE__;
sym_AddSet("_RS", 0)->isBuiltin = true;
#define addNumber(name, val) sym_AddEqu(name, val)->isBuiltin = true
#define addString(name, val) sym_AddString(name, val)->isBuiltin = true
addString("__RGBDS_VERSION__", get_package_version_string());
addNumber("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR);
addNumber("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR);
addNumber("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH);
sym_AddEqu("__RGBDS_MAJOR__", PACKAGE_VERSION_MAJOR)->isBuiltin = true;
sym_AddEqu("__RGBDS_MINOR__", PACKAGE_VERSION_MINOR)->isBuiltin = true;
sym_AddEqu("__RGBDS_PATCH__", PACKAGE_VERSION_PATCH)->isBuiltin = true;
#ifdef PACKAGE_VERSION_RC
addNumber("__RGBDS_RC__", PACKAGE_VERSION_RC);
sym_AddEqu("__RGBDS_RC__", PACKAGE_VERSION_RC)->isBuiltin = true;
#endif
if (now == (time_t)-1) {
@@ -743,19 +750,25 @@ void sym_Init(time_t now)
sizeof(savedTIMESTAMP_ISO8601_UTC), "\"%Y-%m-%dT%H:%M:%SZ\"",
time_utc);
strftime(savedYEAR, sizeof(savedYEAR), "%Y", time_utc);
strftime(savedMONTH, sizeof(savedMONTH), "%m", time_utc);
strftime(savedDAY, sizeof(savedDAY), "%d", time_utc);
strftime(savedHOUR, sizeof(savedHOUR), "%H", time_utc);
strftime(savedMINUTE, sizeof(savedMINUTE), "%M", time_utc);
strftime(savedSECOND, sizeof(savedSECOND), "%S", time_utc);
#define addString(name, val) sym_AddString(name, val)->isBuiltin = true
addString("__TIME__", savedTIME);
addString("__DATE__", savedDATE);
addString("__ISO_8601_LOCAL__", savedTIMESTAMP_ISO8601_LOCAL);
addString("__ISO_8601_UTC__", savedTIMESTAMP_ISO8601_UTC);
addNumber("__UTC_YEAR__", time_utc->tm_year + 1900);
addNumber("__UTC_MONTH__", time_utc->tm_mon + 1);
addNumber("__UTC_DAY__", time_utc->tm_mday);
addNumber("__UTC_HOUR__", time_utc->tm_hour);
addNumber("__UTC_MINUTE__", time_utc->tm_min);
addNumber("__UTC_SECOND__", time_utc->tm_sec);
#undef addNumber
/* This cannot start with zeros */
addString("__UTC_YEAR__", savedYEAR);
addString("__UTC_MONTH__", removeLeadingZeros(savedMONTH));
addString("__UTC_DAY__", removeLeadingZeros(savedDAY));
addString("__UTC_HOUR__", removeLeadingZeros(savedHOUR));
addString("__UTC_MINUTE__", removeLeadingZeros(savedMINUTE));
addString("__UTC_SECOND__", removeLeadingZeros(savedSECOND));
#undef addString
labelScope = NULL;

View File

@@ -15,45 +15,52 @@
#include "extern/utf8decoder.h"
char const *printChar(int c)
/*
* Calculate the hash value for a string.
* Uses the djb2 algorithm (xor version).
* http://www.cse.yorku.ca/~oz/hash.html
*/
uint32_t calchash(const char *s)
{
// "'A'" + '\0': 4 bytes
// "'\\n'" + '\0': 5 bytes
// "0xFF" + '\0': 5 bytes
static char buf[5];
uint32_t hash = 5381;
while (*s != 0)
hash = (hash * 33) ^ (*s++);
return hash;
}
char const *print(int c)
{
static char buf[5]; /* '\xNN' + '\0' */
if (c == EOF)
return "EOF";
if (isprint(c)) {
buf[0] = '\'';
buf[1] = c;
buf[2] = '\'';
buf[3] = '\0';
buf[0] = c;
buf[1] = '\0';
return buf;
}
buf[0] = '\\';
switch (c) {
case '\n':
buf[2] = 'n';
buf[1] = 'n';
break;
case '\r':
buf[2] = 'r';
buf[1] = 'r';
break;
case '\t':
buf[2] = 't';
buf[1] = 't';
break;
default: /* Print as hex */
buf[0] = '0';
buf[1] = 'x';
snprintf(&buf[2], 3, "%02hhX", (uint8_t)c); // includes the '\0'
sprintf(&buf[2], "%02hhx", (uint8_t)c);
return buf;
}
buf[0] = '\'';
buf[1] = '\\';
buf[3] = '\'';
buf[4] = '\0';
buf[2] = '\0';
return buf;
}

View File

@@ -30,7 +30,6 @@ enum WarningState {
static enum WarningState const defaultWarnings[NB_WARNINGS] = {
[WARNING_ASSERT] = WARNING_ENABLED,
[WARNING_BACKWARDS_FOR] = WARNING_DISABLED,
[WARNING_BUILTIN_ARG] = WARNING_DISABLED,
[WARNING_CHARMAP_REDEF] = WARNING_DISABLED,
[WARNING_DIV] = WARNING_DISABLED,
@@ -73,7 +72,6 @@ static enum WarningState warningState(enum WarningID id)
static char const *warningFlags[NB_WARNINGS_ALL] = {
"assert",
"backwards-for",
"builtin-args",
"charmap-redef",
"div",
@@ -102,7 +100,6 @@ enum MetaWarningCommand {
/* Warnings that probably indicate an error */
static uint8_t const _wallCommands[] = {
WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG,
WARNING_CHARMAP_REDEF,
WARNING_EMPTY_DATA_DIRECTIVE,
@@ -122,7 +119,6 @@ static uint8_t const _wextraCommands[] = {
/* Literally everything. Notably useful for testing */
static uint8_t const _weverythingCommands[] = {
WARNING_BACKWARDS_FOR,
WARNING_BUILTIN_ARG,
WARNING_DIV,
WARNING_EMPTY_DATA_DIRECTIVE,

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ static HashType hash(char const *str)
return hash;
}
void **hash_AddElement(HashMap map, char const *key, void *element)
bool hash_AddElement(HashMap map, char const *key, void *element)
{
HashType hashedKey = hash(key);
HalfHashType index = hashedKey;
@@ -61,7 +61,23 @@ void **hash_AddElement(HashMap map, char const *key, void *element)
newEntry->next = map[index];
map[index] = newEntry;
return &newEntry->content;
return newEntry->next != NULL;
}
bool hash_ReplaceElement(HashMap const map, char const *key, void *element)
{
HashType hashedKey = hash(key);
struct HashMapEntry *ptr = map[(HalfHashType)hashedKey];
while (ptr) {
if (hashedKey >> HALF_HASH_NB_BITS == ptr->hash
&& !strcmp(ptr->key, key)) {
ptr->content = element;
return true;
}
ptr = ptr->next;
}
return false;
}
bool hash_RemoveElement(HashMap map, char const *key)
@@ -83,7 +99,7 @@ bool hash_RemoveElement(HashMap map, char const *key)
return false;
}
void **hash_GetNode(HashMap const map, char const *key)
void *hash_GetElement(HashMap const map, char const *key)
{
HashType hashedKey = hash(key);
struct HashMapEntry *ptr = map[(HalfHashType)hashedKey];
@@ -91,20 +107,13 @@ void **hash_GetNode(HashMap const map, char const *key)
while (ptr) {
if (hashedKey >> HALF_HASH_NB_BITS == ptr->hash
&& !strcmp(ptr->key, key)) {
return &ptr->content;
return ptr->content;
}
ptr = ptr->next;
}
return NULL;
}
void *hash_GetElement(HashMap const map, char const *key)
{
void **node = hash_GetNode(map, key);
return node ? *node : NULL;
}
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg)
{
for (size_t i = 0; i < HASHMAP_NB_BUCKETS; i++) {

View File

@@ -106,7 +106,8 @@ static void processLinkerScript(void)
* @param section The section to assign
* @param location The location to assign the section to
*/
static void assignSection(struct Section *section, struct MemoryLocation const *location)
static inline void assignSection(struct Section *section,
struct MemoryLocation const *location)
{
section->org = location->address;
section->bank = location->bank;

View File

@@ -205,7 +205,7 @@ static void cleanup(void)
int main(int argc, char *argv[])
{
int optionChar;
char *endptr; /* For error checking with `strtoul` */
char *endptr; /* For error checking with `strtol` */
unsigned long value; /* For storing `strtoul`'s return value */
/* Parse options */

View File

@@ -452,7 +452,7 @@ static void readAssertion(FILE *file, struct Assertion *assert,
fileName);
}
static struct Section *getMainSection(struct Section *section)
static inline struct Section *getMainSection(struct Section *section)
{
if (section->modifier != SECTION_NORMAL)
section = sect_GetSection(section->name);

View File

@@ -37,7 +37,7 @@ struct RPNStack {
size_t capacity;
} stack;
static void initRPNStack(void)
static inline void initRPNStack(void)
{
stack.capacity = 64;
stack.values = malloc(sizeof(*stack.values) * stack.capacity);
@@ -46,7 +46,7 @@ static void initRPNStack(void)
err(1, "Failed to init RPN stack");
}
static void clearRPNStack(void)
static inline void clearRPNStack(void)
{
stack.size = 0;
}
@@ -92,7 +92,7 @@ static int32_t popRPN(struct FileStackNode const *node, uint32_t lineNo)
return stack.values[stack.size];
}
static void freeRPNStack(void)
static inline void freeRPNStack(void)
{
free(stack.values);
free(stack.errorFlags);

View File

@@ -78,12 +78,12 @@ static bool popFile(void)
return true;
}
static bool isWhiteSpace(int c)
static inline bool isWhiteSpace(int c)
{
return c == ' ' || c == '\t';
}
static bool isNewline(int c)
static inline bool isNewline(int c)
{
return c == '\r' || c == '\n';
}

View File

@@ -54,7 +54,10 @@ void sym_AddSymbol(struct Symbol *symbol)
}
/* If not, add it */
hash_AddElement(symbols, symbol->name, symbol);
bool collided = hash_AddElement(symbols, symbol->name, symbol);
if (beVerbose && collided)
warnx("Symbol hashmap collision occurred!");
}
struct Symbol *sym_GetSymbol(char const *name)

View File

@@ -1,3 +0,0 @@
SECTION UNION "X", WRAM0
SECTION UNION "X", WRAM0, ALIGN[16]

View File

@@ -1,3 +0,0 @@
ERROR: align-unattainable.asm(3):
Section "X"'s alignment cannot be attained in WRAM0
error: Assembly aborted (1 error)!

View File

@@ -1,43 +0,0 @@
macro tickle
; There once was a bug where overwriting worked only on the second try, so
; try everything twice for good measure
; Skip this syntax for EQUS, as it is invalid
IF \2
\1 = 0
\1 = 0
PRINTLN \1
\1 EQU 0
\1 EQU 0
PRINTLN \1
ENDC
PURGE \1
PURGE \1
PRINTLN \1
DEF \1 EQU 0
DEF \1 EQU 0
PRINTLN \1
DEF \1 = 0
DEF \1 = 0
PRINTLN \1
DEF \1 EQUS "hello"
DEF \1 EQUS "hello"
PRINTLN \1
REDEF \1 = 0
REDEF \1 = 0
PRINTLN \1
REDEF \1 EQUS "hello"
REDEF \1 EQUS "hello"
PRINTLN \1
endm
; Representative numeric and string builtins
tickle __LINE__, 1
tickle __FILE__, 0

View File

@@ -1,57 +0,0 @@
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(7):
'__LINE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(8):
'__LINE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(11):
'__LINE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(12):
'__LINE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(16):
Built-in symbol '__LINE__' cannot be purged
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(17):
Built-in symbol '__LINE__' cannot be purged
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(20):
'__LINE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(21):
'__LINE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(24):
'__LINE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(25):
'__LINE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(28):
'__LINE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(29):
'__LINE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(32):
'__LINE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(33):
'__LINE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(36):
'__LINE__' already defined as non-EQUS at <builtin>
ERROR: builtin-overwrite.asm(42) -> builtin-overwrite.asm::tickle(37):
'__LINE__' already defined as non-EQUS at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(16):
Built-in symbol '__FILE__' cannot be purged
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(17):
Built-in symbol '__FILE__' cannot be purged
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(20):
'__FILE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(21):
'__FILE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(24):
'__FILE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(25):
'__FILE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(28):
'__FILE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(29):
'__FILE__' already defined at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(32):
'__FILE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(33):
'__FILE__' already defined as constant at <builtin>
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(36):
Built-in symbol '__FILE__' cannot be redefined
ERROR: builtin-overwrite.asm(43) -> builtin-overwrite.asm::tickle(37):
Built-in symbol '__FILE__' cannot be redefined
error: Assembly aborted (28 errors)!

View File

@@ -1,14 +0,0 @@
$9
$D
$12
$16
$1A
$1E
$22
$26
builtin-overwrite.asm
builtin-overwrite.asm
builtin-overwrite.asm
builtin-overwrite.asm
builtin-overwrite.asm
builtin-overwrite.asm

View File

@@ -1,62 +1,36 @@
def _ASM equ 0
_ASM equ 0
test: MACRO
; Test RGBASM
redef V equs "_ASM +"
; Test RGBASM
V equs "_ASM +"
static_assert \#
; Test RGBLINK
redef V equs "_LINK +"
PURGE V
; Test RGBLINK
V equs "_LINK +"
assert \#
PURGE V
ENDM
test_mod: MACRO
def x = \1 ; dividend
def y = \2 ; divisor
shift 2
def q = x / y ; quotient
def r = x % y ; remainder
; identity laws
test (V (q * y + r)) == (V x)
test (V (x + y) % y) == (V r)
test (V (x - y) % y) == (V r)
ENDM
for x, -300, 301
for y, -x - 1, x + 2
if y != 0
q = x / y
r = x % y
test (V (q * y + r)) == (V x)
test (V (x + y) % y) == (V r)
test (V (x - y) % y) == (V r)
endc
endr
endr
test_each_mod: MACRO
test_mod (\1), (\2)
test_mod (\1), -(\2)
test_mod -(\1), (\2)
test_mod -(\1), -(\2)
ENDM
test_pow: MACRO
def x = \1 ; dividend
def y = 2 ** \2 ; divisor
def r = x % y ; remainder
def m = x & (y - 1) ; mask
; identity law
test (V r) == (V m)
ENDM
test_each_pow: MACRO
test_pow (\1), (\2)
test_pow -(\1), (\2)
ENDM
test_each_mod 0, 1
test_each_mod 7, 5
test_each_mod 42, 256
test_each_mod 567, 256
test_each_mod 256, 512
test_each_mod 1, 65535
test_each_mod 100, 65535
test_each_mod 10000, 65535
test_each_mod 1000000, 65535
test_each_pow 5, 1
test_each_pow 42, 8
test_each_pow 567, 8
test_each_pow 12345, 16
test_each_pow 99999, 16
for x, -300, 301
for p, 31
y = 2 ** p
r = x % y
m = x & (y - 1)
test (V r) == (V m)
endr
endr
SECTION "LINK", ROM0
_LINK::

View File

@@ -3,6 +3,5 @@ warning: equs-newline.asm(3): [-Wuser]
while expanding symbol "ACT"
warning: equs-newline.asm(3): [-Wuser]
Second
while expanding symbol "ACT"
warning: equs-newline.asm(4): [-Wuser]
Third

View File

@@ -1,2 +1,6 @@
recurse EQUS "recurse"
recurse EQUS "recurse "
recurse
; FIXME: also handle the following:
; recurse EQUS "recurse"
; recurse

View File

@@ -1,6 +0,0 @@
test: MACRO
v equs "X"
X equs "" ; should not be expanded
\1
ENDM
test v 0

View File

@@ -1,3 +0,0 @@
ERROR: expand-empty-string.asm(6) -> expand-empty-string.asm::test(4):
syntax error, unexpected number
error: Assembly aborted (1 error)!

View File

@@ -1,3 +0,0 @@
ERROR: expand-empty-string.asm(6) -> expand-empty-string.asm::test(4):
syntax error
error: Assembly aborted (1 error)!

View File

@@ -1,5 +0,0 @@
SECTION "test", ROM0[0]
ld [ $ff00 + c ], a
; 257 spaces exceeds both LEXER_BUF_SIZE (42) and uint8_t limit (255)
ld [ $ff00 + c ], a
ld [ $ff00 + c ], a

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD>

View File

@@ -8,17 +8,13 @@ for v, 0
endr
for v, 2, 1
print "backwards"
print "unreached"
endr
for v, 1, 2, 0
print "unreached"
endr
for v, 1, 2, -1
print "backwards"
endr
for x, 1, 5+1
print "{d:x} "
endr

View File

@@ -1,10 +1,6 @@
warning: for.asm(12): [-Wbackwards-for]
FOR goes backwards from 2 to 1 by 1
ERROR: for.asm(16):
FOR cannot have a step value of 0
warning: for.asm(20): [-Wbackwards-for]
FOR goes backwards from 1 to 2 by -1
ERROR: for.asm(45) -> for.asm::REPT~4(51):
'v' already defined as constant at for.asm(45) -> for.asm::REPT~4(49)
FATAL: for.asm(45) -> for.asm::REPT~4(51):
ERROR: for.asm(41) -> for.asm::REPT~4(47):
'v' already defined as constant at for.asm(41) -> for.asm::REPT~4(45)
FATAL: for.asm(41) -> for.asm::REPT~4(47):
Failed to update FOR symbol value

View File

@@ -1,15 +0,0 @@
num equ 42
fix equ 123.0
str equs "hello"
println "{#0260x:num}"
println "{#-260x:num}"
println "{0280.260f:fix}"
println "{260s:str}"
println "{-260s:str}"
println "<{#0260x:num}>"
println "<{#-260x:num}>"
println "<{0280.260f:fix}>"
println "<{260s:str}>"
println "<{-260s:str}>"

View File

@@ -1,35 +0,0 @@
ERROR: format-truncation.asm(5):
Formatted numeric value too long
ERROR: format-truncation.asm(6):
Formatted numeric value too long
ERROR: format-truncation.asm(7):
Fractional width 260 too long, limiting to 255
ERROR: format-truncation.asm(7):
Formatted numeric value too long
ERROR: format-truncation.asm(8):
Formatted string value too long
ERROR: format-truncation.asm(9):
Formatted string value too long
ERROR: format-truncation.asm(11):
Formatted numeric value too long
warning: format-truncation.asm(11): [-Wlong-string]
String constant too long
ERROR: format-truncation.asm(12):
Formatted numeric value too long
warning: format-truncation.asm(12): [-Wlong-string]
String constant too long
ERROR: format-truncation.asm(13):
Fractional width 260 too long, limiting to 255
ERROR: format-truncation.asm(13):
Formatted numeric value too long
warning: format-truncation.asm(13): [-Wlong-string]
String constant too long
ERROR: format-truncation.asm(14):
Formatted string value too long
warning: format-truncation.asm(14): [-Wlong-string]
String constant too long
ERROR: format-truncation.asm(15):
Formatted string value too long
warning: format-truncation.asm(15): [-Wlong-string]
String constant too long
error: Assembly aborted (12 errors)!

View File

@@ -1,10 +0,0 @@
$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a
$2a
123.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
hello
hello
<$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
<$2a
<123.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
< hell
<hello

View File

@@ -1,4 +0,0 @@
; It seems that \1 was the easiest way to notice the memory corruption that
; resulted from this overflow
x = 0
{.99999999f:x}\1

View File

@@ -1,9 +0,0 @@
ERROR: interpolation-overflow.asm(4):
Fractional width 99999999 too long, limiting to 255
ERROR: interpolation-overflow.asm(4):
Formatted numeric value too long
warning: interpolation-overflow.asm(4): [-Wlarge-constant]
Precision of fixed-point constant is too large
while expanding symbol "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
FATAL: interpolation-overflow.asm(4):
Macro argument '\1' not defined

View File

@@ -1,2 +0,0 @@
recurse EQUS "\{recurse\}"
{recurse}

View File

@@ -1,67 +0,0 @@
FATAL: interpolation-recursion.asm(2):
Recursion limit (64) exceeded
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"
while expanding symbol "{recurse}"

View File

@@ -1,11 +0,0 @@
SECTION "Test", ROM0
MACRO a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
println "truncated :("
ENDM
a012:
a012.local
a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012:
a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012.local

View File

@@ -1,7 +0,0 @@
warning: local-truncated.asm(10): [-Wlong-string]
Symbol name too long, got truncated
ERROR: local-truncated.asm(10):
'a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001' already defined at local-truncated.asm(3)
warning: local-truncated.asm(11): [-Wlong-string]
Symbol name too long, got truncated
error: Assembly aborted (1 error)!

View File

@@ -1 +0,0 @@
truncated :(

View File

@@ -0,0 +1,2 @@
_NARG = 0
_NARG = 0

View File

@@ -0,0 +1,5 @@
ERROR: narg-overwrite.asm(1):
'_NARG' already defined as constant at <builtin>
ERROR: narg-overwrite.asm(2):
'_NARG' already defined as constant at <builtin>
error: Assembly aborted (2 errors)!

View File

@@ -1,6 +0,0 @@
def foo equs "bar"
def bar equs "qux"
MACRO test
\1
ENDM
test foo 0

View File

@@ -1,3 +0,0 @@
ERROR: nested-expansions.asm(6) -> nested-expansions.asm::test(4):
Macro "qux" not defined
error: Assembly aborted (1 error)!

View File

@@ -1,3 +0,0 @@
def s equs "s"
; 65 nested {}s, recursion limit is 64
println "{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{s}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}"

View File

@@ -1,2 +0,0 @@
FATAL: nested-interpolation-recursion.asm(3):
Recursion limit (64) exceeded

View File

@@ -1,6 +0,0 @@
; Triggering a charmap realloc while the charmap has been pushed onto the stack used
; to induce a use-after-free.
pushc
charmap "000000000000000000000000000000000",12
popc
charmap "000000000000000000000000000000000",34

View File

@@ -1,13 +1,13 @@
MACRO N
N:MACRO
FOR I,_NARG
PRINT STRSUB("\n\"\\ INRST1,ABCDEFGHMnOPU_+-()",\1+1,1)
SHIFT
ENDR
SHIFT I
PRINT STRSUB("\n\"\\ INRT1,ABCDEFGHMOPSUn_(+-:)",\1+1,1)
SHIFT-I
REPT I-1
ENDR
REPT _NARG-1
PRINT"\1,"
SHIFT
ENDR
PRINT"\1\n"
ENDM
N 19,11,13,6,21,3,5,0,16,21,6,3,4,10,24,5,11,6,17,0,22,6,4,5,8,3,7,8,6,7,23,12,27,1,2,20,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,1,10,2,9,25,9,10,9,28,0,7,18,4,16,8,0,15,5,14,6,0,7,18,4,16,8,26,4,0,6,15,22,8,3,4,26,9,0,22,6,4,5,8,1,2,9,10,1,0,7,18,4,16,8,0,15,5,14,6,0,22,6,4,5,8,1,2,9,2,20,1,0,15,5,14,19,0,3,5,3
N 5,28,18,10,12,6,19,0,15,19,6,3,4,9,24,5,10,6,16,0,21,17,4,15,7,3,4,0,20,6,4,5,7,3,21,7,6,21,22,11,25,1,2,23,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,1,9,2,8,26,8,9,8,29,0,21,17,4,15,7,27,4,0,14,5,13,6,0,6,14,20,7,3,24,5,10,6,16,27,8,0,20,6,4,5,7,1,2,8,9,1,0,21,17,4,15,7,0,14,5,13,6,0,20,6,4,5,7,1,2,8,2,23,1,0,14,5,13,18,0,3,5,3

View File

@@ -1,13 +1,13 @@
MACRO N
N:MACRO
FOR I,_NARG
PRINT STRSUB("\n\"\\ INRST1,ABCDEFGHMnOPU_+-()",\1+1,1)
SHIFT
ENDR
SHIFT I
PRINT STRSUB("\n\"\\ INRT1,ABCDEFGHMOPSUn_(+-:)",\1+1,1)
SHIFT-I
REPT I-1
ENDR
REPT _NARG-1
PRINT"\1,"
SHIFT
ENDR
PRINT"\1\n"
ENDM
N 19,11,13,6,21,3,5,0,16,21,6,3,4,10,24,5,11,6,17,0,22,6,4,5,8,3,7,8,6,7,23,12,27,1,2,20,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,1,10,2,9,25,9,10,9,28,0,7,18,4,16,8,0,15,5,14,6,0,7,18,4,16,8,26,4,0,6,15,22,8,3,4,26,9,0,22,6,4,5,8,1,2,9,10,1,0,7,18,4,16,8,0,15,5,14,6,0,22,6,4,5,8,1,2,9,2,20,1,0,15,5,14,19,0,3,5,3
N 5,28,18,10,12,6,19,0,15,19,6,3,4,9,24,5,10,6,16,0,21,17,4,15,7,3,4,0,20,6,4,5,7,3,21,7,6,21,22,11,25,1,2,23,2,1,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,1,9,2,8,26,8,9,8,29,0,21,17,4,15,7,27,4,0,14,5,13,6,0,6,14,20,7,3,24,5,10,6,16,27,8,0,20,6,4,5,7,1,2,8,9,1,0,21,17,4,15,7,0,14,5,13,6,0,20,6,4,5,7,1,2,8,2,23,1,0,14,5,13,18,0,3,5,3

View File

@@ -1,4 +1,4 @@
macro q
q:macro
println\1,"\1"
endm
q"macro q\nprintln\\1,\"\\1\"\nendm\n q"
q"q:macro\nprintln\\1,\"\\1\"\nendm\n q"

View File

@@ -1,4 +1,4 @@
macro q
q:macro
println\1,"\1"
endm
q"macro q\nprintln\\1,\"\\1\"\nendm\n q"
q"q:macro\nprintln\\1,\"\\1\"\nendm\n q"

View File

@@ -16,8 +16,12 @@ SECTION "calls", ROM0[0]
defRST: MACRO
SECTION "rst\1", ROM0[$\1]
rst\1:
; FIXME: This is required, otherwise the lexer does not paste the two tokens
ADDR equs "$\1"
SECTION "rst\1", ROM0[ADDR]
rst\1:
PURGE ADDR
ENDM
defRST 00
defRST 08

View File

@@ -38,14 +38,12 @@ tryCmp () {
# Add the version constants test, outputting the closest tag to the HEAD
if git describe --tags --abbrev=0 > version.out; then
$RGBASM --version >> version.out
cat > version.asm <<EOF
IF !DEF(__RGBDS_RC__)
PRINTLN "v{d:__RGBDS_MAJOR__}.{d:__RGBDS_MINOR__}.{d:__RGBDS_PATCH__}"
ELSE
PRINTLN "v{d:__RGBDS_MAJOR__}.{d:__RGBDS_MINOR__}.{d:__RGBDS_PATCH__}-rc{d:__RGBDS_RC__}"
ENDC
PRINTLN "rgbasm {__RGBDS_VERSION__}"
EOF
else
echo "${bold}${orange}Warning: cannot run version test!${rescolors}${resbold}"
@@ -62,7 +60,6 @@ EOF
cat > quote\"file.err <<EOF
warning: quote"file.asm(1): [-Wuser]
quote"file.asm
while expanding symbol "__FILE__"
EOF
fi

View File

@@ -1,27 +1,19 @@
warning: unique-id.asm(12) -> unique-id.asm::m(4): [-Wuser]
_u1
while expanding symbol "warn_unique"
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
_u2
while expanding symbol "warn_unique"
warning: unique-id.asm(12) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
_u3
while expanding symbol "warn_unique"
warning: unique-id.asm(12) -> unique-id.asm::m(8): [-Wuser]
_u1
while expanding symbol "warn_unique"
warning: unique-id.asm(14) -> unique-id.asm::m(4): [-Wuser]
_u4
while expanding symbol "warn_unique"
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~1(6): [-Wuser]
_u5
while expanding symbol "warn_unique"
warning: unique-id.asm(14) -> unique-id.asm::m(5) -> unique-id.asm::m::REPT~2(6): [-Wuser]
_u6
while expanding symbol "warn_unique"
warning: unique-id.asm(14) -> unique-id.asm::m(8): [-Wuser]
_u4
while expanding symbol "warn_unique"
FATAL: unique-id.asm(15):
Macro argument '\@' not defined
while expanding symbol "warn_unique"

View File

@@ -1,14 +0,0 @@
MACRO between
assert (\1) <= (\2) && (\2) <= (\3)
ENDM
between 0, __UTC_YEAR__, 9999 ; Y10K problem...
between 1, __UTC_MONTH__, 12
between 1, __UTC_DAY__, 31
between 0, __UTC_HOUR__, 23
between 0, __UTC_MINUTE__, 59
between 0, __UTC_SECOND__, 60 ; leap seconds!
UTC_TIME EQUS STRCAT("{04d:__UTC_YEAR__}-{02d:__UTC_MONTH__}-{02d:__UTC_DAY__}T", \
"{02d:__UTC_HOUR__}:{02d:__UTC_MINUTE__}:{02d:__UTC_SECOND__}Z")
assert !STRCMP("{UTC_TIME}", __ISO_8601_UTC__)

View File

View File

View File

@@ -14,8 +14,12 @@ SECTION "calls", ROM0[0]
defRST: MACRO
SECTION "rst\1", ROM0[$\1]
rst\1:
; FIXME: This is required, otherwise the lexer does not paste the two tokens
ADDR equs "$\1"
SECTION "rst\1", ROM0[ADDR]
rst\1:
PURGE ADDR
ENDM
defRST 00
defRST 08

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
export LC_ALL=C
set -o pipefail

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/bin/bash
# Return failure as soon as a command fails to execute