Compare commits

...

54 Commits

Author SHA1 Message Date
ISSOtm
ede982b50a Bump patch level appropriately
*HEADDESK*
2020-12-09 20:30:31 +01:00
ISSOtm
319d775c13 Add CI script to create docs on new releases 2020-12-09 16:08:43 +01:00
ISSOtm
44124319a6 Work around old Bison versions not forward-declaring yyparse
Notably, macOS still ships 2.3 (from 2008)...
Should fix #214
2020-12-09 16:00:22 +01:00
ISSOtm
462fd7539c Prohibit nested macros
After discussion (starting there:
https://github.com/gbdev/rgbds/pull/594#issuecomment-706437458
), it was decided that plain nested macros should not be
allowed.
Since #590 is fixed, EQUS can be used as a workaround;
multiline strings (#589) will make that easier on the
user when implemented.
Fixes #588, supersedes and closes #594.
Additionally, closes #388.
2020-12-09 10:44:39 +01:00
ISSOtm
f16e34b804 Fix captures beginning in expansions
Fixes #590
2020-12-09 09:54:55 +01:00
ISSOtm
c3ccdc548e Remove unnecessary flex dep from Dockerfile 2020-12-09 09:42:19 +01:00
ISSOtm
fd721ca480 Document optional RB/RW/RL argument 2020-12-09 09:39:46 +01:00
ISSOtm
eac365aef0 Allow argument to rb, rw and rl to be optional
Fixes #617
2020-12-09 09:31:47 +01:00
ISSOtm
4de6266442 Add explanation of how EXPORT works
Fixes #608
2020-12-08 21:07:24 +01:00
ISSOtm
213d985e17 Fix incorrect "sliced" INCBIN causing memory leaks
Oh, how I miss RAII...
2020-11-29 12:47:53 +01:00
ISSOtm
de76dcb8fb Fix possible segfault from -MT and -MQ
Happened only if `malloc` failed, so...
2020-11-29 12:47:53 +01:00
Eldred Habert
30fb6bde5e Merge pull request #615 from ISSOtm/find-sym
Create specialized symbol finder functions
2020-11-25 15:17:34 +01:00
ISSOtm
4f842a1248 Create specialized symbol finder functions
The old "find symbol with auto scope" function is now three:
- One finds the exact name passed to it, skipping any checks
  This is useful e.g. if such checks were already performed.
- One checks that the name is not scoped, and calls the first.
  This is useful for names that cannot be scoped, such as checking for EQUS.
  Doing this instead of the third should improve performance somehwat, since
  this specific case is hit by the lexer each time an identifier is read.
- The last one checks if the name should be expanded (`.loc` → `Glob.loc`),
  and that the local part is not scoped. This is essentially the old function.
2020-11-21 01:06:17 +01:00
ISSOtm
cc4d455b8a Add test for empty local label component 2020-11-21 00:58:40 +01:00
Eldred Habert
0bb5efebfd Merge pull request #610 from daid/stdin
Allow rgbasm and rgblink to use stdout and stdin as input and output
2020-11-08 01:20:44 +01:00
ISSOtm
b6bf7ae620 Fix RGBLINK incorrectly reading file stack nodes
This caused node IDs to mismatch, yielding possibly corrupted file stacks
Worst part is, the docs mentioned the reading order had to be reversed...
2020-11-04 02:52:06 +01:00
ISSOtm
dc96cc6d1e Add zsh completion scripts
Can't get bash ones to work, but these do.
2020-11-03 23:29:47 +01:00
daid
642daf1a76 Update main.c 2020-11-03 13:33:57 +01:00
daid
84edfb3d88 Update output.c 2020-11-03 13:33:02 +01:00
Daid
7e620bff81 Allow rgbasm and rgblink to use stdout and stdin as input and output 2020-10-26 20:28:15 +01:00
ISSOtm
0c55703438 Improve helpers.h
Use C11 standard _Noreturn instead of attributes (except, of course, MSVC)
Remove unused helpers
Avoid trapping in release builds, in favor of just unreachability
Improve shim when __builtin_* are not available
2020-10-26 15:19:31 +01:00
ISSOtm
6c57ad2226 Have make clean delete parser artifacts
Forgot to update the names there
2020-10-25 16:26:58 +01:00
ISSOtm
9028fb5391 Fix mistakes in RGBDS man pages
As reported by `mandoc -Wall`
2020-10-23 01:02:59 +02:00
ISSOtm
12dc49b60a Make page processor print usage only after reporting all bad opts 2020-10-23 00:40:05 +02:00
Eldred Habert
7e1d20acdf Merge pull request #607 from anderoonies/inline-comment-#537
handle inline c-like comments in lexer
2020-10-19 19:36:49 +02:00
anderoonies
5230104852 documentation for block comments 2020-10-19 18:05:37 +02:00
anderoonies
55be77be69 discard block comments delimited with /* */ 2020-10-15 12:42:53 -04:00
Eldred Habert
42b3a17356 Merge pull request #602 from NieDzejkob/shiftstorm
Report only one error when invalid shift has argument
2020-10-13 15:48:16 +02:00
Jakub Kądziołka
4e1d79081c Improve error message for negative shift arguments 2020-10-13 15:42:16 +02:00
ISSOtm
4ce4fdec71 Mention setting CMAKE_BUILD_TYPE to Release when using CMake
Not *necessary*, but if you don't know better, you should probably use it.
Fixes rgbds-www#9
2020-10-13 11:37:25 +02:00
Eldred Habert
05256946ac Merge pull request #604 from NieDzejkob/narg-overwrite
Don't overwrite symbol when it's not allowed
2020-10-13 10:47:57 +02:00
Eldred Habert
73396166aa Merge pull request #605 from NieDzejkob/invalid-labels
Don't consider difference of invalid labels constant
2020-10-13 10:42:05 +02:00
Jakub Kądziołka
4c5d5c7085 Don't consider difference of invalid labels constant
If a label is defined outside of a section, avoid trying to obtain its
value.
2020-10-12 23:03:14 +02:00
Jakub Kądziołka
045a9e8b93 Report only one error when invalid shift has argument
Not to mention that incrementing a variable in a loop is kinda dumb.
2020-10-12 22:54:20 +02:00
Jakub Kądziołka
4419f0d54f remove dead function: sym_GetDefinedValue 2020-10-12 13:31:21 +02:00
Jakub Kądziołka
b07aa00d5c Don't overwrite symbol when it's not allowed
When a user tried to overwrite a builtin symbol, it would change its
type despite the error, making the second try succeed. This is
problematic, as the location of a builtin symbol cannot be updated.
2020-10-12 12:35:49 +02:00
Eldred Habert
e4f5df1306 Merge pull request #603 from NieDzejkob/rpn-realloc
reserveSpace: don't assume one doubling is enough
2020-10-12 12:26:44 +02:00
Jakub Kądziołka
dc62d60e9b reserveSpace: don't assume one doubling is enough 2020-10-12 11:57:03 +02:00
ISSOtm
71d8aeb4c2 Add CMake defines to enable tracing lexer and parser 2020-10-12 09:02:21 +02:00
Eldred Habert
0836f67d42 Merge pull request #601 from NieDzejkob/utf8decoder
utf8decoder: Use byte-sized byte argument
2020-10-12 01:49:57 +02:00
Eldred Habert
176a57a1e9 Merge pull request #600 from NieDzejkob/stray-shift
Report error when shifting outside a macro
2020-10-12 01:44:10 +02:00
Eldred Habert
0d02355dbf Merge pull request #599 from NieDzejkob/stray-align
Report error when aligning outside of a section
2020-10-12 01:43:35 +02:00
Jakub Kądziołka
6767d11c23 utf8decoder: Use byte-sized byte argument
This prevents passing a negative value out of a signed char by accident.
Also renders some casts in the code superfluous.
2020-10-12 01:22:09 +02:00
ISSOtm
2dd9015dc6 Remove two stale variables from parser.y
They were made useless with the lexer rewrite
2020-10-12 00:52:12 +02:00
Jakub Kądziołka
217c10ddac Report error when shifting outside a macro 2020-10-12 00:47:01 +02:00
Jakub Kądziołka
822e4e7c44 Report error when aligning outside of a section 2020-10-12 00:27:54 +02:00
ISSOtm
0b1d01792d Indicate cur offset in linkerscript "backwards org" message 2020-10-12 00:04:08 +02:00
ISSOtm
01637768cf Rename asmy to more explicit parser
This should make the purpose of that file clearer to newcomers
2020-10-11 21:03:41 +02:00
ISSOtm
6a8ae643d5 Mention that SHIFT updates _NARG
Fixes #598
2020-10-11 02:13:30 +02:00
ISSOtm
fd83d46ba0 Enable master docs update workflow always
There seems to be no way to make the check work, and Actions are disabled
in forks by default anyways.
2020-10-11 02:04:09 +02:00
ISSOtm
914856342c Fix incorrect documentation of accepted sym names
No, they cannot start with a digit!
2020-10-11 01:57:27 +02:00
Eldred Habert
91889fc14a Merge pull request #593 from Rangi42/issue586
Fix #586: Update the `charmaps` hashmap when an existing charmap is resized
2020-10-10 02:15:04 +02:00
Rangi
7c8ec5a5ed Add a test case for charmaps that segfaults prior to this fix 2020-10-09 20:06:02 -04:00
Rangi
effc6788eb Fix #586 segfault: Update the charmaps hashmap when an existing charmap is resized 2020-10-07 13:21:13 -04:00
94 changed files with 764 additions and 301 deletions

View File

@@ -26,14 +26,12 @@ while getopts ":hr" opt; do
;;
\?)
echo "Unknown option '$OPTARG'"
if [ $bad_usage -eq 0 ]; then
usage
bad_usage=1
fi
;;
esac
done
if [ $bad_usage -ne 0 ]; then
usage
exit 1
fi
shift $(($OPTIND - 1))

View File

@@ -0,0 +1,54 @@
name: "Create release docs"
on:
release:
types:
- created
jobs:
build:
runs-on: ubuntu-18.04
steps:
- name: Checkout rgbds@master
uses: actions/checkout@v2
with:
repository: gbdev/rgbds
ref: master
path: rgbds
- name: Checkout rgbds-www@master
uses: actions/checkout@v2
with:
repository: gbdev/rgbds-www
ref: master
path: rgbds-www
- name: Build and install mandoc
run: |
sudo apt-get -qq update
sudo apt-get install -yq zlib1g-dev
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
tar xf mandoc-1.14.5.tar.gz
cd mandoc-1.14.5
./configure
make
sudo make install
- name: Update pages
working-directory: rgbds
run: |
./.github/actions/get-pages.sh ../rgbds-www/_documentation ${GITHUB_REF}
- name: Push new pages
working-directory: rgbds-www
run: |
mkdir -p -m 700 ~/.ssh
echo "${{ secrets.SSH_KEY_SECRET }}" > ~/.ssh/id_ed25519
chmod 0600 ~/.ssh/id_ed25519
eval $(ssh-agent -s)
ssh-add ~/.ssh/id_ed25519
git config --global user.name "GitHub Action"
git config --global user.email "community@gbdev.io"
git add .
git commit -m "Create RGBDS ${GITHUB_REF} documentation"
if git remote | grep -q origin; then
git remote set-url origin git@github.com:gbdev/rgbds-www.git
else
git remote add origin git@github.com:gbdev/rgbds-www.git
fi
git push origin master

View File

@@ -17,7 +17,6 @@ on:
jobs:
build:
if: secrets.SSH_KEY_SECRET != ''
runs-on: ubuntu-18.04
steps:
- name: Checkout rgbds@master

View File

@@ -27,6 +27,8 @@ include_directories("${PROJECT_SOURCE_DIR}/include")
option(SANITIZERS "Build with sanitizers enabled" OFF)
option(MORE_WARNINGS "Turn on more warnings" OFF)
option(TRACE_PARSER "Trace parser execution" OFF)
option(TRACE_LEXER "Trace lexer execution" OFF)
if(MSVC)
add_compile_options(/W1 /MP)
@@ -69,3 +71,11 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED True)
add_subdirectory(src)
if(TRACE_PARSER)
target_compile_definitions(rgbasm PRIVATE -DYYDEBUG)
endif()
if(TRACE_LEXER)
target_compile_definitions(rgbasm PRIVATE -DLEXER_DEBUG)
endif()

View File

@@ -8,7 +8,6 @@ FROM alpine:latest
RUN apk add --update \
build-base \
byacc \
flex \
libpng-dev
COPY . /rgbds
WORKDIR /rgbds

View File

@@ -53,13 +53,13 @@ RM := rm -rf
all: rgbasm rgblink rgbfix rgbgfx
rgbasm_obj := \
src/asm/asmy.o \
src/asm/charmap.o \
src/asm/fstack.o \
src/asm/lexer.o \
src/asm/macro.o \
src/asm/main.o \
src/asm/math.o \
src/asm/parser.o \
src/asm/output.o \
src/asm/rpn.o \
src/asm/section.o \
@@ -72,7 +72,7 @@ rgbasm_obj := \
src/hashmap.o \
src/linkdefs.o
src/asm/lexer.o src/asm/main.o: src/asm/asmy.h
src/asm/lexer.o src/asm/main.o: src/asm/parser.h
rgblink_obj := \
src/link/assign.o \
@@ -136,7 +136,7 @@ clean:
$Q${RM} rgbgfx rgbgfx.exe
$Qfind src/ -name "*.o" -exec rm {} \;
$Q${RM} rgbshim.sh
$Q${RM} src/asm/asmy.c src/asm/asmy.h
$Q${RM} src/asm/parser.c src/asm/parser.h
# Target used to install the binaries and man pages.

View File

@@ -32,7 +32,7 @@ is possible using ``make`` or ``cmake``; follow the link for more detailed instr
.. code:: sh
cmake -S . -B build
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --install build
@@ -50,6 +50,8 @@ The RGBDS source code file structure somewhat resembles the following:
│   └── workflows/
│      └── ...
├── contrib/
│   ├── zsh_compl/
│   │   └── ...
│   └── ...
├── include/
│   └── ...
@@ -79,6 +81,8 @@ The RGBDS source code file structure somewhat resembles the following:
- ``contrib/`` - scripts and other resources which may be useful to users and developers of
RGBDS.
* ``zsh_compl`` contains tab completion scripts for use with zsh. Put them somewhere in your ``fpath``, and they should auto-load.
- ``include/`` - header files for each respective C files in `src`.
- ``src/`` - source code and manual pages for RGBDS.

49
contrib/zsh_compl/_rgbasm Normal file
View File

@@ -0,0 +1,49 @@
#compdef rgbasm
_rgbasm_warnings() {
local warnings=(
'error:Turn all warnings into errors'
'all:Enable most warning messages'
'extra:Enable extra, possibly unwanted, messages'
'everything:Enable literally everything'
'assert:Warn when WARN-type asserts fail'
'builtin-args:Report incorrect args to built-in funcs'
'div:Warn when dividing the smallest int by -1'
'empty-entry:Warn on empty entries in db, dw, dl args'
'large-constant:Warn on constants too large for a signed 32-bit int'
'long-string:Warn on strings too long'
'obsolete:Warn when using deprecated features'
'shift:Warn when shifting negative values'
'shift-amount:Warn when a shift'\''s operand it negative or \> 32'
'truncation:Warn when implicit truncations lose bits'
'user:Warn when executing the WARN built-in'
)
# TODO: handle `no-` and `error=` somehow?
_describe warning warnings
}
local args=(
# Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number]'
'(-E --export-all)'{-E,--export-all}'[Export all symbols]'
'(-h --halt-without-nop)'{-h,--halt-without-nop}'[Avoid outputting a `nop` after `halt`]'
'(-L ---preserve-ld)'{-L,--preserve-ld}'[Prevent auto-optimizing `ld` into `ldh`]'
'(-v --verbose)'{-v,--verbose}'[Print additional messages regarding progression]'
-w'[Disable all warnings]'
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
'(-D --define)'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
'(-i --include)'{-i,--include}'+[Add an include directory]:include path:_files -/'
'(-M --dependfile)'{-M,--dependfile}"+[List deps in make format]:output file:_files -g '*.{d,mk}"
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings'
'*'":assembly sources:_files -g '*.asm'"
)
_arguments -s -S : $args

25
contrib/zsh_compl/_rgbfix Normal file
View File

@@ -0,0 +1,25 @@
#compdef rgbfix
local args=(
# Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number]'
'(-C --color-only)'{-C,--color-only}'[Mark ROM as GBC-only]'
'(-c --color-compatible)'{-c,--color-compatible}'[Mark ROM as GBC-compatible]'
'(-j --non-japanese)'{-j,--non-japanese}'[Set the non-Japanese region flag]'
'(-s --sgb-compatible)'{-s,--sgb-compatible}'[Set the SGB flag]'
'(-f --fix-spec -v --validate)'{-v,--validate}'[Shorthand for -f lhg]'
'(-f --fix-spec -v --validate)'{-f,--fix-spec}'+[Fix or trash some header values]:fix spec:'
'(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:'
'(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:'
'(-l --old-licensee)'{-l,--old-licensee}'+[Set old licensee ID]:licensee number:'
'(-m --mbc-type)'{-m,--mbc-type}'+[Set MBC flags]:mbc flags byte:'
'(-n --rom-version)'{-n,--rom-version}'+[Set ROM version]:rom version byte:'
'(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:'
'(-r --ram-size)'{-r,--ram-size}'+[Set RAM size]:ram size byte:'
'(-t --title)'{-t,--title}'+[Set title string]:11-char title string:'
'*'":ROM files:_files -g '*.{gb,sgb,gbc}'"
)
_arguments -s -S : $args

37
contrib/zsh_compl/_rgbgfx Normal file
View File

@@ -0,0 +1,37 @@
#compdef rgbgfx
_depths() {
local depths=(
'1:1bpp'
'2:2bpp (native)'
)
_describe 'bit depth' depths
}
local args=(
# Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number]'
'(-a --attr-map -A --output-attr-map)'{-A,--output-attr-map}'[Shortcut for -a <file>.attrmap]'
'(-C --color-curve)'{-C,--color-curve}'[Generate palettes using GBC color curve]'
'(-D --debug)'{-D,--debug}'[Enable debug features]'
'(-f --fix -F --fix-and-save)'{-f,--fix}'[Fix input PNG into an indexed image]'
'(-f --fix -F --fix-and-save)'{-F,--fix-and-save}'[Like -f but also save CLI params within the PNG]'
'(-h --horizontal)'{-h,--horizontal}'[Lay out tiles horizontally instead of vertically]'
'(-m --mirror-tiles)'{-m,--mirror-tiles}'[Eliminate mirrored tiles from output]'
'(-p --palette -P --output-palette)'{-P,--output-palette}'[Shortcut for -p <file>.pal]'
'(-t --tilemap -T --output-tilemap)'{-T,--output-tilemap}'[Shortcut for -t <file>.tilemap]'
'(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]'
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
'(-a --attr-map -A --output-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files'
'(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths'
'(-o --output)'{-o,--output}'+[Set output file]:output file:_files'
'(-p --palette -P --output-palette)'{-p,--palette}"+[Output the image's palette in little-endian native RGB555 format]:palette file:_files"
'(-t --tilemap -T --output-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
'(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:'
'*'":input png files:_files -g '*.png'"
)
_arguments -s -S : $args

View File

@@ -0,0 +1,22 @@
#compdef rgblink
local args=(
# Arguments are listed here in the same order as in the manual, except for the version
'(- : * options)'{-V,--version}'[Print version number]'
'(-d --dmg)'{-d,--dmg}'[Enable DMG mode (-w + no VRAM banking)]'
'(-t --tiny)'{-t,--tiny}'[Enable tiny mode, disabling ROM banking]'
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
'(-w --wramx)'{-w,--wramx}'[Disable WRAM banking]'
'(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'"
'(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'"
'(-n --sym)'(-n,--sym)"+[Produce a symbol file]:sym file:_files -g '*.sym'"
'(-O --overlay)'{-O,--overlay}'+[Overlay sections over on top of bin file]:base overlay:_files'
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
'(-s --smart)'{-s,--smart}'+[!BROKEN! Perform smart linking from this symbol]:symbol name:'
'*'":object files:_files -g '*.o'"
)
_arguments -s -S : $args

View File

@@ -29,7 +29,7 @@ uint32_t macro_GetUniqueID(void);
char const *macro_GetUniqueIDStr(void);
void macro_SetUniqueID(uint32_t id);
uint32_t macro_UseNewUniqueID(void);
void macro_ShiftCurrentArgs(void);
void macro_ShiftCurrentArgs(int32_t count);
uint32_t macro_NbArgs(void);
#endif

View File

@@ -27,7 +27,7 @@ struct Expression {
uint32_t nRPNPatchSize; // Size the expression will take in the obj file
};
/* FIXME: Should be defined in `asmy.h`, but impossible with POSIX Yacc */
/* FIXME: Should be defined in `parser.h`, but impossible with POSIX Yacc */
extern int32_t nPCOffset;
/*
@@ -46,7 +46,7 @@ static inline bool rpn_isSymbol(const struct Expression *expr)
return expr->isSymbol;
}
void rpn_Symbol(struct Expression *expr, char *tzSym);
void rpn_Symbol(struct Expression *expr, char const *tzSym);
void rpn_Number(struct Expression *expr, uint32_t i);
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
struct Symbol const *rpn_SymbolOf(struct Expression const *expr);

View File

@@ -121,11 +121,22 @@ struct Symbol *sym_AddSet(char const *symName, int32_t value);
uint32_t sym_GetPCValue(void);
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
uint32_t sym_GetConstantValue(char const *s);
struct Symbol *sym_FindSymbol(char const *symName);
/*
* Find a symbol by exact name, bypassing expansion checks
*/
struct Symbol *sym_FindExactSymbol(char const *name);
/*
* Find a symbol by exact name; may not be scoped, produces an error if it is
*/
struct Symbol *sym_FindUnscopedSymbol(char const *name);
/*
* Find a symbol, possibly scoped, by name
*/
struct Symbol *sym_FindScopedSymbol(char const *name);
struct Symbol const *sym_GetPC(void);
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
struct Symbol *sym_Ref(char const *symName);
struct Symbol *sym_AddString(char const *symName, char const *value);
uint32_t sym_GetDefinedValue(char const *s);
void sym_Purge(char const *symName);
void sym_Init(void);

View File

@@ -22,6 +22,7 @@ enum WarningID {
WARNING_EMPTY_ENTRY, /* Empty entry in `db`, `dw` or `dl` */
WARNING_LARGE_CONSTANT, /* Constants too large */
WARNING_LONG_STR, /* String too long for internal buffers */
WARNING_NESTED_COMMENT, /* Comment-start delimeter in a block comment */
WARNING_OBSOLETE, /* Obsolete things */
WARNING_SHIFT, /* Shifting undefined behavior */
WARNING_SHIFT_AMOUNT, /* Strange shift amount */
@@ -54,7 +55,7 @@ void warning(enum WarningID id, const char *fmt, ...);
* It is also used when the assembler goes into an invalid state (for example,
* when it fails to allocate memory).
*/
noreturn_ void fatalerror(const char *fmt, ...);
_Noreturn void fatalerror(const char *fmt, ...);
/*
* Used for errors that make it impossible to assemble correctly, but don't

View File

@@ -34,10 +34,10 @@ void vwarn(const char *fmt, va_list ap) format_(printf, 1, 0);
void warnx(const char *fmt, ...) format_(printf, 1, 2);
void vwarnx(const char *fmt, va_list ap) format_(printf, 1, 0);
noreturn_ void err(int status, const char *fmt, ...) format_(printf, 2, 3);
noreturn_ void verr(int status, const char *fmt, va_list ap) format_(printf, 2, 0);
noreturn_ void errx(int status, const char *fmt, ...) format_(printf, 2, 3);
noreturn_ void verrx(int status, const char *fmt, va_list ap) format_(printf, 2, 0);
_Noreturn void err(int status, const char *fmt, ...) format_(printf, 2, 3);
_Noreturn void verr(int status, const char *fmt, va_list ap) format_(printf, 2, 0);
_Noreturn void errx(int status, const char *fmt, ...) format_(printf, 2, 3);
_Noreturn void verrx(int status, const char *fmt, va_list ap) format_(printf, 2, 0);
#endif /* ERR_IN_LIBC */

View File

@@ -9,6 +9,6 @@
#ifndef EXTERN_UTF8DECODER_H
#define EXTERN_UTF8DECODER_H
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte);
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
#endif /* EXTERN_UTF8DECODER_H */

View File

@@ -33,6 +33,16 @@ typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
*/
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.
* @param map The HashMap to remove the element from

View File

@@ -9,21 +9,30 @@
#ifndef HELPERS_H
#define HELPERS_H
#ifdef __GNUC__
/* GCC or compatible */
#define format_(archetype, str_index, first_arg) \
__attribute__ ((format (archetype, str_index, first_arg)))
#define noreturn_ __attribute__ ((noreturn))
#define trap_ __builtin_trap()
#else
/* Unsupported, but no need to throw a fit */
#define format_(archetype, str_index, first_arg)
#define noreturn_
#define unused_
#define trap_
// Of course, MSVC does not support C11, so no _Noreturn there...
#ifdef _MSC_VER
#define _Noreturn __declspec(noreturn)
#endif
/* Macros for stringification */
// Ideally, we'd use `__has_attribute` and `__has_builtin`, but these were only introduced in GCC 9
#ifdef __GNUC__ // GCC or compatible
#define format_(archetype, str_index, first_arg) \
__attribute__ ((format (archetype, str_index, first_arg)))
// In release builds, define "unreachable" as such, but trap in debug builds
#ifdef NDEBUG
#define unreachable_ __builtin_unreachable
#else
#define unreachable_ __builtin_trap
#endif
#else
// Unsupported, but no need to throw a fit
#define format_(archetype, str_index, first_arg)
// This seems to generate similar code to __builtin_unreachable, despite different semantics
// Note that executing this is undefined behavior (declared _Noreturn, but does return)
static inline _Noreturn unreachable_(void) {}
#endif
// Macros for stringification
#define STR(x) #x
#define EXPAND_AND_STR(x) STR(x)

View File

@@ -66,7 +66,7 @@ void warning(struct FileStackNode const *where, uint32_t lineNo,
void error(struct FileStackNode const *where, uint32_t lineNo,
char const *fmt, ...) format_(printf, 3, 4);
noreturn_ void fatal(struct FileStackNode const *where, uint32_t lineNo,
_Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo,
char const *fmt, ...) format_(printf, 3, 4);
/**

View File

@@ -11,7 +11,7 @@
#define PACKAGE_VERSION_MAJOR (0)
#define PACKAGE_VERSION_MINOR (4)
#define PACKAGE_VERSION_PATCH (1)
#define PACKAGE_VERSION_PATCH (2)
const char *get_package_version_string(void);

View File

@@ -22,13 +22,13 @@ else()
pkg_check_modules(LIBPNG REQUIRED libpng)
endif()
BISON_TARGET(ASMy "asm/asmy.y"
"${PROJECT_SOURCE_DIR}/src/asm/asmy.c"
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/asm/asmy.h"
BISON_TARGET(PARSER "asm/parser.y"
"${PROJECT_SOURCE_DIR}/src/asm/parser.c"
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/asm/parser.h"
)
set(rgbasm_src
"${BISON_ASMy_OUTPUT_SOURCE}"
"${BISON_PARSER_OUTPUT_SOURCE}"
"asm/charmap.c"
"asm/fstack.c"
"asm/lexer.c"

4
src/asm/.gitignore vendored
View File

@@ -1,2 +1,2 @@
asmy.c
asmy.h
/parser.c
/parser.h

View File

@@ -173,6 +173,7 @@ void charmap_Add(char *mapping, uint8_t value)
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 */

View File

@@ -317,7 +317,7 @@ void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
{
dbgPrint("Running macro \"%s\"\n", macroName);
struct Symbol *macro = sym_FindSymbol(macroName);
struct Symbol *macro = sym_FindExactSymbol(macroName);
if (!macro) {
error("Macro \"%s\" not defined\n", macroName);

View File

@@ -36,7 +36,7 @@
#include "asm/util.h"
#include "asm/warning.h"
/* Include this last so it gets all type & constant definitions */
#include "asmy.h" /* For token definitions, generated from asmy.y */
#include "parser.h" /* For token definitions, generated from parser.y */
#ifdef LEXER_DEBUG
#define dbgPrint(...) fprintf(stderr, "[lexer] " __VA_ARGS__)
@@ -921,6 +921,33 @@ void lexer_DumpStringExpansions(void)
free(stack);
}
/* Discards an block comment */
static void discardBlockComment(void)
{
dbgPrint("Discarding block comment\n");
for (;;) {
switch (nextChar()) {
case EOF:
error("Unterminated block comment\n");
return;
case '/':
if (peek(0) == '*') {
warning(WARNING_NESTED_COMMENT,
"/* in block comment\n");
}
continue;
case '*':
if (peek(0) == '/') {
shiftChars(1);
return;
}
/* fallthrough */
default:
continue;
}
}
}
/* Function to discard all of a line's comments */
static void discardComment(void)
@@ -1284,7 +1311,7 @@ static char const *readInterpolation(void)
}
symName[i] = '\0';
struct Symbol const *sym = sym_FindSymbol(symName);
struct Symbol const *sym = sym_FindScopedSymbol(symName);
if (!sym) {
error("Interpolated symbol \"%s\" does not exist\n", symName);
@@ -1476,8 +1503,6 @@ static int yylex_NORMAL(void)
return T_OP_ADD;
case '-':
return T_OP_SUB;
case '/':
return T_OP_DIV;
case '~':
return T_OP_NOT;
@@ -1498,7 +1523,14 @@ static int yylex_NORMAL(void)
/* Handle ambiguous 1- or 2-char tokens */
char secondChar;
case '/': /* Either division or a block comment */
secondChar = peek(0);
if (secondChar == '*') {
shiftChars(1);
discardBlockComment();
break;
}
return T_OP_DIV;
case '|': /* Either binary or logical OR */
secondChar = peek(0);
if (secondChar == '|') {
@@ -1659,9 +1691,10 @@ static int yylex_NORMAL(void)
if (tokenType != T_ID && tokenType != T_LOCAL_ID)
return tokenType;
if (lexerState->expandStrings) {
/* Local symbols cannot be string expansions */
if (tokenType == T_ID && lexerState->expandStrings) {
/* Attempt string expansion */
struct Symbol const *sym = sym_FindSymbol(yylval.tzSym);
struct Symbol const *sym = sym_FindExactSymbol(yylval.tzSym);
if (sym && sym->type == SYM_EQUS) {
char const *s = sym_GetStringValue(sym);
@@ -1929,13 +1962,11 @@ restart:
static char *startCapture(void)
{
assert(!lexerState->expansions);
lexerState->capturing = true;
lexerState->captureSize = 0;
lexerState->disableMacroArgs = true;
if (lexerState->isMmapped) {
if (lexerState->isMmapped && !lexerState->expansions) {
return &lexerState->ptr[lexerState->offset];
} else {
lexerState->captureCapacity = 128; /* The initial size will be twice that */
@@ -2014,7 +2045,6 @@ finish:
void lexer_CaptureMacroBody(char **capture, size_t *size)
{
char *captureStart = startCapture();
unsigned int level = 0;
int c = peek(0);
/* If the file is `mmap`ed, we need not to unmap it to keep access to the macro */
@@ -2051,27 +2081,7 @@ void lexer_CaptureMacroBody(char **capture, size_t *size)
} while (isWhitespace(c));
/* Now, try to match either `REPT` or `ENDR` as a **whole** identifier */
if (startsIdentifier(c)) {
switch (readIdentifier(c)) {
case T_ID:
/* We have an initial label, look for a single colon */
do {
c = nextChar();
} while (isWhitespace(c));
if (c != ':') /* If not a colon, give up */
break;
/* And finally, a `MACRO` token */
do {
c = nextChar();
} while (isWhitespace(c));
if (!startsIdentifier(c))
break;
if (readIdentifier(c) != T_POP_MACRO)
break;
level++;
break;
case T_POP_ENDM:
if (!level) {
if (readIdentifier(c) == T_POP_ENDM) {
/* Read (but don't capture) until EOL or EOF */
lexerState->capturing = false;
do {
@@ -2085,8 +2095,6 @@ void lexer_CaptureMacroBody(char **capture, size_t *size)
shiftChars(1);
goto finish;
}
level--;
}
}
lexerState->lineNo++;
}

View File

@@ -128,10 +128,17 @@ uint32_t macro_UseNewUniqueID(void)
return maxUniqueID;
}
void macro_ShiftCurrentArgs(void)
void macro_ShiftCurrentArgs(int32_t count)
{
if (macroArgs->shift != macroArgs->nbArgs)
macroArgs->shift++;
if (!macroArgs) {
error("Cannot shift macro arguments outside of a macro\n");
} else if (count < 0) {
error("Cannot shift arguments by negative amount %" PRId32 "\n", count);
} else if (macroArgs->shift < macroArgs->nbArgs) {
macroArgs->shift += count;
if (macroArgs->shift > macroArgs->nbArgs)
macroArgs->shift = macroArgs->nbArgs;
}
}
uint32_t macro_NbArgs(void)

View File

@@ -26,7 +26,7 @@
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asm/warning.h"
#include "asmy.h"
#include "parser.h"
#include "extern/err.h"
#include "extern/getopt.h"
@@ -34,6 +34,10 @@
#include "helpers.h"
#include "version.h"
// Old Bison versions (confirmed for 2.3) do not forward-declare `yyparse` in the generated header
// Unfortunately, macOS still ships 2.3, which is from 2008...
int yyparse(void);
size_t cldefines_index;
size_t cldefines_numindices;
size_t cldefines_bufsize;
@@ -432,6 +436,7 @@ int main(int argc, char *argv[])
/* On first alloc, make an empty str */
tzTargetFileName =
malloc(nTargetFileNameLen + 1);
if (tzTargetFileName)
*tzTargetFileName = '\0';
} else {
tzTargetFileName =

View File

@@ -296,6 +296,11 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
uint8_t rpndata = popbyte();
switch (rpndata) {
struct Symbol *sym;
uint32_t value;
uint8_t b;
size_t i;
case RPN_CONST:
writebyte(RPN_CONST);
writebyte(popbyte());
@@ -303,13 +308,15 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
writebyte(popbyte());
writebyte(popbyte());
break;
case RPN_SYM:
{
for (unsigned int i = -1; (tzSym[++i] = popbyte()); )
;
struct Symbol *sym = sym_FindSymbol(tzSym);
uint32_t value;
case RPN_SYM:
i = 0;
do {
tzSym[i] = popbyte();
} while (tzSym[i++]);
// The symbol name is always written expanded
sym = sym_FindExactSymbol(tzSym);
if (sym_IsConstant(sym)) {
writebyte(RPN_CONST);
value = sym_GetConstantValue(tzSym);
@@ -317,18 +324,22 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
writebyte(RPN_SYM);
value = getSymbolID(sym);
}
writebyte(value & 0xFF);
writebyte(value >> 8);
writebyte(value >> 16);
writebyte(value >> 24);
break;
}
case RPN_BANK_SYM:
{
for (unsigned int i = -1; (tzSym[++i] = popbyte()); )
;
struct Symbol *sym = sym_FindSymbol(tzSym);
uint32_t value = getSymbolID(sym);
i = 0;
do {
tzSym[i] = popbyte();
} while (tzSym[i++]);
// The symbol name is always written expanded
sym = sym_FindExactSymbol(tzSym);
value = getSymbolID(sym);
writebyte(RPN_BANK_SYM);
writebyte(value & 0xFF);
@@ -336,18 +347,15 @@ static void writerpn(uint8_t *rpnexpr, uint32_t *rpnptr, uint8_t *rpn,
writebyte(value >> 16);
writebyte(value >> 24);
break;
}
case RPN_BANK_SECT:
{
uint8_t b;
case RPN_BANK_SECT:
writebyte(RPN_BANK_SECT);
do {
b = popbyte();
writebyte(b);
} while (b != 0);
break;
}
default:
writebyte(rpndata);
break;
@@ -471,7 +479,11 @@ static void registerExportedSymbol(struct Symbol *symbol, void *arg)
*/
void out_WriteObject(void)
{
FILE *f = fopen(tzObjectname, "wb");
FILE *f;
if (strcmp(tzObjectname, "-") != 0)
f = fopen(tzObjectname, "wb");
else
f = fdopen(1, "wb");
if (!f)
err(1, "Couldn't write file '%s'", tzObjectname);

View File

@@ -36,8 +36,6 @@
#include "platform.h" // strncasecmp, strdup
uint32_t nListCountEmpty;
char *tzNewMacro;
uint32_t ulNewMacroSize;
int32_t nPCOffset;
bool executeElseBlock; /* If this is set, ELIFs cannot be executed anymore */
@@ -63,7 +61,7 @@ static size_t strlenUTF8(const char *s)
uint32_t codep = 0;
while (*s) {
switch (decode(&state, &codep, (uint8_t)*s)) {
switch (decode(&state, &codep, *s)) {
case 1:
fatalerror("STRLEN: Invalid UTF-8 character\n");
break;
@@ -97,7 +95,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
/* Advance to starting position in source string. */
while (src[srcIndex] && curPos < pos) {
switch (decode(&state, &codep, (uint8_t)src[srcIndex])) {
switch (decode(&state, &codep, src[srcIndex])) {
case 1:
fatalerror("STRSUB: Invalid UTF-8 character\n");
break;
@@ -115,7 +113,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
/* Copy from source to destination. */
while (src[srcIndex] && destIndex < MAXSTRLEN && curLen < len) {
switch (decode(&state, &codep, (uint8_t)src[srcIndex])) {
switch (decode(&state, &codep, src[srcIndex])) {
case 1:
fatalerror("STRSUB: Invalid UTF-8 character\n");
break;
@@ -184,6 +182,7 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
%type <sVal> relocexpr_no_str
%type <nConstValue> const
%type <nConstValue> uconst
%type <nConstValue> rs_uconst
%type <nConstValue> const_3bit
%type <sVal> reloc_8bit
%type <sVal> reloc_8bit_no_str
@@ -581,13 +580,8 @@ assert : T_POP_ASSERT assert_type relocexpr
}
;
shift : T_POP_SHIFT { macro_ShiftCurrentArgs(); }
| T_POP_SHIFT uconst
{
int32_t i = $2;
while (i--)
macro_ShiftCurrentArgs();
}
shift : T_POP_SHIFT { macro_ShiftCurrentArgs(1); }
| T_POP_SHIFT const { macro_ShiftCurrentArgs($2); }
;
load : T_POP_LOAD string ',' sectiontype sectorg sectattrs {
@@ -623,19 +617,27 @@ rsset : T_POP_RSSET uconst { sym_AddSet("_RS", $2); }
rsreset : T_POP_RSRESET { sym_AddSet("_RS", 0); }
;
rl : T_LABEL T_POP_RL uconst {
rs_uconst : /* empty */ {
$$ = 1;
}
| uconst {
$$ = $1;
}
;
rl : T_LABEL T_POP_RL rs_uconst {
sym_AddEqu($1, sym_GetConstantValue("_RS"));
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 4 * $3);
}
;
rw : T_LABEL T_POP_RW uconst {
rw : T_LABEL T_POP_RW rs_uconst {
sym_AddEqu($1, sym_GetConstantValue("_RS"));
sym_AddSet("_RS", sym_GetConstantValue("_RS") + 2 * $3);
}
;
rb : T_LABEL T_POP_RB uconst {
rb : T_LABEL T_POP_RB rs_uconst {
sym_AddEqu($1, sym_GetConstantValue("_RS"));
sym_AddSet("_RS", sym_GetConstantValue("_RS") + $3);
}
@@ -939,7 +941,7 @@ relocexpr_no_str : scoped_id { rpn_Symbol(&$$, $1); }
| T_OP_DEF {
lexer_ToggleStringExpansion(false);
} '(' scoped_id ')' {
struct Symbol const *sym = sym_FindSymbol($4);
struct Symbol const *sym = sym_FindScopedSymbol($4);
rpn_Number(&$$, !!sym);

View File

@@ -12,7 +12,6 @@
.Nm rgbasm
.Nd language documentation
.Sh DESCRIPTION
.Pp
This is the full description of the language used by
.Xr rgbasm 1 .
The description of the instructions supported by the Game Boy CPU is in
@@ -30,7 +29,6 @@ but any program that processes RGB object files (described in
.Xr rgbds 5 )
can be used in its place.
.Sh SYNTAX
.Pp
The syntax is linebased, just as in any other assembler, meaning that you do one instruction or pseudoop per line:
.Pp
.Dl Oo Ar label Oc Oo Ar instruction Oc Oo Ar ;\ comment Oc
@@ -47,13 +45,23 @@ The assembler
.Em always
ignores comments and their contents.
.Pp
There are two syntaxes for comments. The most common is that anything that follows a semicolon
There are three syntaxes for comments.
The most common is that anything that follows a semicolon
.Ql \&;
not inside a string, is a comment until the end of the line.
The other is that lines beginning with a
The second is a block comment, beginning with
.Ql /*
and ending with
.Ql */ .
It can be split across multiple lines, or occur in the middle of an expression:
.Bd -literal -offset indent
X = /* the value of x
should be 3 */ 3
.Ed
The third is that lines beginning with a
.Ql *
(not even spaces before it) are ignored.
This second syntax is deprecated (will be removed in a future version) and should be replaced with the first one.
This third syntax is deprecated (will be removed in a future version) and should be replaced with either of the first two.
.Pp
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:
@@ -72,7 +80,6 @@ like this:
"world!")
.Ed
.Sh EXPRESSIONS
.Pp
An expression can be composed of many things.
Numerical expressions are always evaluated using signed 32-bit math.
Zero is considered to be the only "false" number, all non-zero numbers (including negative) are "true".
@@ -86,9 +93,7 @@ section.
.Pp
The instructions in the macro-language generally require constant expressions.
.Ss Numeric Formats
.Pp
There are a number of numeric formats.
.Pp
.Bl -column -offset indent "Fixed point (16.16)" "Prefix"
.It Sy Format type Ta Sy Prefix Ta Sy Accepted characters
.It Hexadecimal Ta $ Ta 0123456789ABCDEF
@@ -119,9 +124,7 @@ is equivalent to
.Pp
You can also use symbols, which are implicitly replaced with their value.
.Ss Operators
.Pp
A great number of operators you can use in expressions are available (listed from highest to lowest precedence):
.Pp
.Bl -column -offset indent "!= == <= >= < >"
.It Sy Operator Ta Sy Meaning
.It Li \&( \&) Ta Precedence override
@@ -167,7 +170,6 @@ and
.Pp
! returns 1 if the operand was 0, and 0 otherwise.
.Ss Fixedpoint Expressions
.Pp
Fixed-point numbers are basically normal (32-bit) integers, which count 65536th's instead of entire units, offering better precision than integers but limiting the range of values.
The upper 16 bits are used for the integer part and the lower 16 bits are used for the fraction (65536ths).
Since they are still akin to integers, you can use them in normal integer expressions, and some integer operators like
@@ -182,7 +184,6 @@ The following functions are designed to operate with fixed-point numbers:
.EQ
delim $$
.EN
.Pp
.Bl -column -offset indent "ATAN2(x, y)"
.It Sy Name Ta Sy Operation
.It Fn DIV x y Ta $x \[di] y$
@@ -213,7 +214,6 @@ ANGLE = ANGLE + 256.0 ; 256 = 65536 / table_len, with table_len = 256
ENDR
.Ed
.Ss String Expressions
.Pp
The most basic string expression is any number of characters contained in double quotes
.Pq Ql \&"for instance" .
The backslash character
@@ -222,8 +222,7 @@ is special in that it causes the character following it to be
.Dq escaped ,
meaning that it is treated differently from normal.
There are a number of escape sequences you can use within a string:
.Pp
.Bl -column -offset indent "'\1' - '\9'"
.Bl -column -offset indent "Qo \[rs]1 Qc \[en] Qo \[rs]9 Qc"
.It Sy String Ta Sy Meaning
.It Ql \[rs]\[rs] Ta Produces a backslash
.It Ql \[rs]" Ta Produces a double quote without terminating
@@ -278,7 +277,6 @@ The symbol's value is again inserted directly.
.Pp
The following functions operate on string expressions.
Most of them return a string, however some of these functions actually return an integer and can be used as part of an integer expression!
.Pp
.Bl -column "STRSUB(str, pos, len)"
.It Sy Name Ta Sy Operation
.It Fn STRLEN string Ta Returns the number of characters in Ar string .
@@ -290,7 +288,6 @@ Most of them return a string, however some of these functions actually return an
.It Fn STRLWR str Ta Converts all characters in Ar str No to lower case and returns the new string.
.El
.Ss Character maps
.Pp
When writing text that is meant to be displayed in the Game Boy, the characters used in the source code may have a different encoding than the default of ASCII.
For example, the tiles used for uppercase letters may be placed starting at tile index 128, which makes it difficult to add text strings to the ROM.
.Pp
@@ -325,9 +322,7 @@ This means that any string that the code may want to print as debug information
The output value of a mapping can be 0.
If this happens, the assembler will treat this as the end of the string and the rest of it will be trimmed.
.Ss Other functions
.Pp
There are a few other functions that do various useful things:
.Pp
.Bl -column "DEF(label)"
.It Sy Name Ta Sy Operation
.It Fn BANK arg Ta Returns a bank number.
@@ -356,7 +351,6 @@ String symbols are not expanded within the parentheses.
or 0 if only RGBLINK can compute its value.
.El
.Sh SECTIONS
.Pp
Before you can start writing code, you must define a section.
This tells the assembler what kind of information follows and, if it is code, where to put it.
.Pp
@@ -373,7 +367,6 @@ All other sections must have a unique name, even in different source files, or t
Possible section
.Ar type Ns s
are as follows:
.Pp
.Bl -tag
.It Ic ROM0
A ROM section.
@@ -559,7 +552,6 @@ SECTION "VRAM Data",ROMX,BANK[2],ALIGN[4] ;\ align to 16 bytes
.Ed
.El
.Ss Section Stack
.Pp
.Ic POPS
and
.Ic PUSHS
@@ -572,7 +564,6 @@ will push the current section context on the section stack.
can then later be used to restore it.
Useful for defining sections in included files when you don't want to override the section context at the point the file was included.
.Ss RAM Code
.Pp
Sometimes you want to have some code in RAM.
But then you can't simply put it in a RAM section, you have to store it in ROM and copy it to RAM at some point.
.Pp
@@ -633,7 +624,6 @@ You cannot nest
.Ic LOAD
blocks, nor can you change the current section within them.
.Ss Unionized Sections
.Pp
When you're tight on RAM, you may want to define overlapping blocks of variables, as explained in the
.Sx Unions
section.
@@ -727,12 +717,11 @@ and the one from
.Ql bar.o
last.
.Sh SYMBOLS
.Pp
RGBDS supports several types of symbols:
.Pp
.Bl -hang
.It Sy Label
Numerical symbol designating a memory location. May or may not have a value known at assembly time.
Numerical symbol designating a memory location.
May or may not have a value known at assembly time.
.It Sy Constant
Numerical symbol whose value has to be known at assembly time.
.It Sy Macro
@@ -743,10 +732,16 @@ code that can be invoked later.
String symbol that can be evaluated, similarly to a macro.
.El
.Pp
Symbol names can contain letters, numbers, underscores, hashes and
Symbol names can contain letters, numbers, underscores
.Sq _ ,
hashes
.Sq #
and at signs
.Sq @ .
However, they must begin with either a letter, a number, or an underscore.
Periods are allowed exclusively for labels, as described below.
However, they must begin with either a letter, or an underscore.
Periods
.Sq \&.
are allowed exclusively for labels, as described below.
A symbol cannot have the same name as a reserved keyword.
.Em \&In the line where a symbol is defined there must not be any whitespace before it ,
otherwise
@@ -846,7 +841,6 @@ str_SIZEOF EQU 259
.Ed
.Pp
There are five commands in the RS group of commands:
.Pp
.Bl -column "RSSET constexpr"
.It Sy Command Ta Sy Meaning
.It Ic RSRESET Ta Equivalent to Ql RSSET 0 .
@@ -857,6 +851,12 @@ There are five commands in the RS group of commands:
(In practice, this one cannot be used due to a bug).
.El
.Pp
If the argument to
.Ic RB , RW ,
or
.Ic RL
is omitted, it's assumed to be 1.
.Pp
Note that colons
.Ql \&:
following the name are not allowed.
@@ -923,9 +923,28 @@ Note that a single colon
.Ql \&:
following the macro's name is required.
Macros can't be exported or imported.
.Pp
Plainly nesting macro definitions is not allowed, but this can be worked around using
.Ic EQUS .
This won't work:
.Bd -literal -offset indent
outer: MACRO
inner: MACRO
PRINTT "Hello!\[rs]n"
ENDM
ENDM
.Ed
.Pp
But this will:
.Bd -literal -offset indent
outer: MACRO
definition equs "inner: MACRO\[rs]nPRINTT \[rs]"Hello!\[rs]\[rs]n\[rs]"\[rs]nENDM"
definition
PURGE definition
ENDM
.Ed
.El
.Ss Exporting and importing symbols
.Pp
Importing and exporting of symbols is a feature that is very useful when your project spans many source files and, for example, you need to jump to a routine defined in another file.
.Pp
Exporting of symbols has to be done manually, importing is done automatically if
@@ -937,15 +956,56 @@ The following will cause
and so on to be accessible to other files during the link process:
.Dl Ic EXPORT Ar symbol1 Bq , Ar symbol2 , No ...
.Pp
For example, if you have the following three files:
.Pp
.Ql a.asm :
.Bd -literal -compact
SECTION "a", WRAM0
LabelA:
.Ed
.Pp
.Ql b.asm :
.Bd -literal -compact
SECTION "b", WRAM0
ExportedLabelB1::
ExportedLabelB2:
EXPORT ExportedLabelB2
.Ed
.Pp
.Ql c.asm :
.Bd -literal -compact
SECTION "C", ROM0[0]
dw LabelA
dw ExportedLabelB1
dw ExportedLabelB2
.Ed
.Pp
Then
.Ql c.asm
can use
.Ql ExportedLabelB1
and
.Ql ExportedLabelB2 ,
but not
.Ql LabelA ,
so linking them together will fail:
.Bd -literal
$ rgbasm -o a.o a.asm
$ rgbasm -o b.o b.asm
$ rgbasm -o c.o c.asm
$ rgblink a.o b.o c.o
error: c.asm(2): Unknown symbol "LabelA"
Linking failed with 1 error
.Ed
.Pp
Note also that only exported symbols will appear in symbol and map files produced by
.Xr rgblink 1 .
.Pp
.Ic GLOBAL
is a deprecated synonym for
.Ic EXPORT ,
do not use it.
.Pp
Note also that only exported symbols will appear in symbol and map files produced by
.Xr rgblink 1 .
.Ss Purging symbols
.Pp
.Ic PURGE
allows you to completely remove a symbol from the symbol table as if it had never existed.
.Em USE WITH EXTREME CAUTION!!!
@@ -964,15 +1024,13 @@ Note that, as an exception, string symbols in the argument list of a
command
.Em will not be expanded .
.Ss Predeclared Symbols
.Pp
The following symbols are defined by the assembler:
.Pp
.Bl -column -offset indent "EQUS" "__ISO_8601_LOCAL__"
.It Sy Type Ta Sy Name Ta Sy Contents
.It Ic EQU Ta Dv @ Ta PC value (essentially, the current memory address)
.It Ic EQU Ta Dv _PI Ta Fixed point \[*p]
.It Ic SET Ta Dv _RS Ta _RS Counter
.It Ic EQU Ta Dv _NARG Ta Number of arguments passed to macro
.It Ic EQU Ta Dv _NARG Ta Number of arguments passed to macro, updated by Ic SHIFT
.It Ic EQU Ta Dv __LINE__ Ta The current line number
.It Ic EQUS Ta Dv __FILE__ Ta The current filename
.It Ic EQUS Ta Dv __DATE__ Ta Today's date
@@ -991,7 +1049,6 @@ The following symbols are defined by the assembler:
.El
.Sh DEFINING DATA
.Ss Declaring variables in a RAM section
.Pp
.Ic DS
allocates a number of empty bytes.
This is the preferred method of allocating space in a RAM section.
@@ -1012,7 +1069,6 @@ 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
.Pp
.Ic DB
defines a list of bytes that will be stored in the final image.
Ideal for tables and text.
@@ -1064,7 +1120,6 @@ can be used in a
.Ic SRAM
section.
.Ss Including binary files
.Pp
You probably have some graphics, level data, etc. you'd like to include.
Use
.Ic INCBIN
@@ -1086,9 +1141,9 @@ The example below includes 256 bytes from data.bin, starting from byte 78.
INCBIN "data.bin",78,256
.Ed
.Pp
The length argument is optional. If only the start position is specified, the bytes from the start position until the end of the file will be included.
The length argument is optional.
If only the start position is specified, the bytes from the start position until the end of the file will be included.
.Ss Unions
.Pp
Unions allow multiple memory allocations to overlap, like unions in C.
This does not increase the amount of memory available, but allows re-using the same memory region for different purposes.
.Pp
@@ -1140,7 +1195,6 @@ like commands (see
.Sx Declaring variables in a RAM section ) .
.Sh THE MACRO LANGUAGE
.Ss Invoking macros
.Pp
You execute the macro by inserting its name.
.Bd -literal -offset indent
add a,b
@@ -1202,7 +1256,6 @@ Also, a macro can have inside an
.Sy EQUS
which references the same macro, which has the same problem.
.Pp
.Pp
It's possible to pass arguments to macros as well!
You retrieve the arguments by using the escape sequences
.Ic \[rs]1
@@ -1276,7 +1329,9 @@ is a special command only available in macros.
Very useful in
.Ic REPT
blocks.
It will shift the arguments by one to the left.
It will shift the arguments by one to the left, and decrease
.Dv _NARG
by 1.
.Ic \[rs]1
will get the value of
.Ic \[rs]2 , \[rs]2
@@ -1289,7 +1344,6 @@ This is the only way of accessing the value of arguments from 10 to 256.
.Ic SHIFT
can optionally be given an integer parameter, and will apply the above shifting that number of times.
.Ss Printing things during assembly
.Pp
The next four commands print text and values to the standard output.
Useful for debugging macros, or wherever you may feel the need to tell yourself some important information.
.Bd -literal -offset indent
@@ -1298,7 +1352,6 @@ PRINTI (2 + 3) / 5
PRINTV $FF00 + $F0
PRINTF MUL(3.14, 3987.0)
.Ed
.Pp
.Bl -inset
.It Ic PRINTT
prints out a string.
@@ -1317,7 +1370,6 @@ prints out a fixed point value.
Be careful that none of those automatically print a line feed; if you need one, use
.Ic PRINTT "\[rs]n" .
.Ss Automatically repeating blocks of code
.Pp
Suppose you want to unroll a time consuming loop without copy-pasting it.
.Ic REPT
is here for that purpose.
@@ -1354,7 +1406,6 @@ As in macros, you can also use the escape sequence
.Ic REPT
blocks can be nested.
.Ss Aborting the assembly process
.Pp
.Ic FAIL
and
.Ic WARN
@@ -1375,7 +1426,6 @@ If you need to ensure some assumption is correct when compiling, you can use
and
.Ic STATIC_ASSERT .
Syntax examples are given below:
.Pp
.Bd -literal -offset indent
Function:
xor a
@@ -1426,7 +1476,6 @@ to be emitted;
.Ic FATAL
immediately aborts.
.Ss Including other source files
.Pp
Use
.Ic INCLUDE
to process another assembler file and then return to the current file when done.
@@ -1442,7 +1491,6 @@ calls infinitely (or until you run out of memory, whichever comes first).
INCLUDE "irq.inc"
.Ed
.Ss Conditional assembling
.Pp
The four commands
.Ic IF , ELIF , ELSE ,
and
@@ -1492,7 +1540,6 @@ Also, if there is more than one
block, all of them but the first one are ignored.
.Sh MISCELLANEOUS
.Ss Changing options while assembling
.Pp
.Ic OPT
can be used to change some of the options during assembling from within the source, instead of defining them on the command-line.
.Pp
@@ -1522,7 +1569,6 @@ can then later be used to restore them.
Useful if you want to change some options in an include file and you don't want to destroy the options set by the program that included your file.
The stack's number of entries is limited only by the amount of memory in your machine.
.Ss Requesting alignment
.Pp
While
.Ic ALIGN
as presented in
@@ -1550,7 +1596,6 @@ is a shorthand for
.Xr rgbds 7 ,
.Xr gbz80 7
.Sh HISTORY
.Pp
.Nm
was originally written by Carsten S\(/orensen as part of the ASMotor package,
and was later packaged in RGBDS by Justin Lloyd.

View File

@@ -46,7 +46,8 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
/* If there isn't enough room to reserve the space, realloc */
if (!expr->tRPN)
expr->nRPNCapacity = 256; /* Initial size */
else if (expr->nRPNCapacity >= MAXRPNLEN)
while (expr->nRPNCapacity - expr->nRPNLength < size) {
if (expr->nRPNCapacity >= MAXRPNLEN)
/*
* To avoid generating humongous object files, cap the
* size of RPN expressions
@@ -57,6 +58,7 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
expr->nRPNCapacity = MAXRPNLEN;
else
expr->nRPNCapacity *= 2;
}
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
if (!expr->tRPN)
@@ -102,9 +104,9 @@ void rpn_Number(struct Expression *expr, uint32_t i)
expr->nVal = i;
}
void rpn_Symbol(struct Expression *expr, char *tzSym)
void rpn_Symbol(struct Expression *expr, char const *tzSym)
{
struct Symbol *sym = sym_FindSymbol(tzSym);
struct Symbol *sym = sym_FindScopedSymbol(tzSym);
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
error("PC has no value outside a section\n");
@@ -113,15 +115,15 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
rpn_Init(expr);
expr->isSymbol = true;
sym_Ref(tzSym);
makeUnknown(expr, sym_IsPC(sym) ? "PC is not constant at assembly time"
: "'%s' is not constant at assembly time", tzSym);
sym = sym_Ref(tzSym);
expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */
size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */
size_t nameLen = strlen(sym->name) + 1; /* Don't forget NUL! */
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
*ptr++ = RPN_SYM;
memcpy(ptr, tzSym, nameLen);
memcpy(ptr, sym->name, nameLen);
/* RGBLINK assumes PC is at the byte being computed... */
if (sym_IsPC(sym) && nPCOffset) {
@@ -155,7 +157,7 @@ void rpn_BankSelf(struct Expression *expr)
void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
{
struct Symbol const *sym = sym_FindSymbol(tzSym);
struct Symbol const *sym = sym_FindScopedSymbol(tzSym);
/* The @ symbol is treated differently. */
if (sym_IsPC(sym)) {
@@ -167,10 +169,8 @@ void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
if (sym && !sym_IsLabel(sym)) {
error("BANK argument must be a label\n");
} else {
sym_Ref(tzSym);
if (!sym)
/* If the symbol didn't exist, `sym_Ref` created it */
sym = sym_FindSymbol(tzSym);
sym = sym_Ref(tzSym);
assert(sym); // If the symbol didn't exist, it should have been created
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != -1) {
/* Symbol's section is known and bank is fixed */
@@ -179,10 +179,10 @@ void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
makeUnknown(expr, "\"%s\"'s bank is not known", tzSym);
expr->nRPNPatchSize += 5; /* opcode + 4-byte sect ID */
size_t nameLen = strlen(tzSym) + 1; /* Room for NUL! */
size_t nameLen = strlen(sym->name) + 1; /* Room for NUL! */
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
*ptr++ = RPN_BANK_SYM;
memcpy(ptr, tzSym, nameLen);
memcpy(ptr, sym->name, nameLen);
}
}
}
@@ -296,7 +296,7 @@ struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
{
if (!rpn_isSymbol(expr))
return NULL;
return sym_FindSymbol((char *)expr->tRPN + 1);
return sym_FindScopedSymbol((char *)expr->tRPN + 1);
}
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
@@ -307,7 +307,9 @@ bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
return false;
return sym_GetSection(sym1) == sym_GetSection(sym);
struct Section const *section1 = sym_GetSection(sym1);
struct Section const *section2 = sym_GetSection(sym);
return section1 && (section1 == section2);
}
static bool isDiffConstant(struct Expression const *src1,

View File

@@ -378,6 +378,7 @@ uint32_t sect_GetOutputOffset(void)
void sect_AlignPC(uint8_t alignment, uint16_t offset)
{
checksection();
struct Section *sect = sect_GetSymbolSection();
if (sect->org != -1) {
@@ -619,7 +620,7 @@ void out_PCRelByte(struct Expression *expr)
{
checkcodesection();
reserveSpace(1);
struct Symbol const *pc = sym_FindSymbol("@");
struct Symbol const *pc = sym_GetPC();
if (!rpn_IsDiffConstant(expr, pc)) {
createPatch(PATCHTYPE_JR, expr);
@@ -662,9 +663,9 @@ void out_BinaryFile(char const *s, int32_t startPos)
if (fstk_FindFile(s, &fullPath, &size))
f = fopen(fullPath, "rb");
free(fullPath);
if (!f) {
free(fullPath);
if (oGeneratedMissingIncludes) {
oFailedOnMissingInclude = true;
return;
@@ -681,6 +682,7 @@ void out_BinaryFile(char const *s, int32_t startPos)
if (startPos >= fsize) {
error("Specified start position is greater than length of file\n");
fclose(f);
return;
}
@@ -705,7 +707,6 @@ void out_BinaryFile(char const *s, int32_t startPos)
error("Error reading INCBIN file '%s': %s\n", s, strerror(errno));
fclose(f);
free(fullPath);
}
void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length)

View File

@@ -222,32 +222,42 @@ static void fullSymbolName(char *output, size_t outputSize,
fatalerror("Symbol name is too long: '%s%s'\n", scopeName, localName);
}
/*
* Find a symbol by name and scope
*/
static struct Symbol *findsymbol(char const *s, char const *scope)
struct Symbol *sym_FindExactSymbol(char const *name)
{
return hash_GetElement(symbols, name);
}
struct Symbol *sym_FindUnscopedSymbol(char const *name)
{
if (strchr(name, '.')) {
error("Expected non-scoped symbol name, not \"%s\"\n", name);
return NULL;
}
return sym_FindExactSymbol(name);
}
struct Symbol *sym_FindScopedSymbol(char const *name)
{
char const *dotPtr = strchr(name, '.');
if (dotPtr) {
if (strchr(dotPtr + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n",
name);
/* If auto-scoped local label, expand the name */
if (dotPtr == name) { /* Meaning, the name begins with the dot */
char fullname[MAXSYMLEN + 1];
if (s[0] == '.' && scope) {
fullSymbolName(fullname, sizeof(fullname), s, scope);
s = fullname;
fullSymbolName(fullname, sizeof(fullname), name, labelScope);
return sym_FindExactSymbol(fullname);
}
}
return sym_FindExactSymbol(name);
}
char const *separator = strchr(s, '.');
if (separator && strchr(separator + 1, '.'))
fatalerror("'%s' is a nonsensical reference to a nested local symbol\n", s);
return hash_GetElement(symbols, s);
}
/*
* Find a symbol by name, with automatically determined scope
*/
struct Symbol *sym_FindSymbol(char const *symName)
struct Symbol const *sym_GetPC(void)
{
return findsymbol(symName, symName[0] == '.' ? labelScope : NULL);
return PCSymbol;
}
static inline bool isReferenced(struct Symbol const *sym)
@@ -260,7 +270,7 @@ static inline bool isReferenced(struct Symbol const *sym)
*/
void sym_Purge(char const *symName)
{
struct Symbol *symbol = sym_FindSymbol(symName);
struct Symbol *symbol = sym_FindScopedSymbol(symName);
if (!symbol) {
error("'%s' not defined\n", symName);
@@ -312,7 +322,7 @@ uint32_t sym_GetConstantSymValue(struct Symbol const *sym)
*/
uint32_t sym_GetConstantValue(char const *s)
{
struct Symbol const *sym = sym_FindSymbol(s);
struct Symbol const *sym = sym_FindScopedSymbol(s);
if (sym == NULL)
error("'%s' not defined\n", s);
@@ -322,23 +332,6 @@ uint32_t sym_GetConstantValue(char const *s)
return 0;
}
/*
* Return a defined symbols value... aborts if not defined yet
*/
uint32_t sym_GetDefinedValue(char const *s)
{
struct Symbol const *sym = sym_FindSymbol(s);
if (sym == NULL || !sym_IsDefined(sym))
error("'%s' not defined\n", s);
else if (!sym_IsNumeric(sym))
error("'%s' is a macro or string symbol\n", s);
else
return sym_GetValue(sym);
return 0;
}
char const *sym_GetCurrentSymbolScope(void)
{
return labelScope;
@@ -356,11 +349,11 @@ void sym_SetCurrentSymbolScope(char const *newScope)
*/
static struct Symbol *createNonrelocSymbol(char const *symbolName)
{
struct Symbol *symbol = findsymbol(symbolName, NULL);
struct Symbol *symbol = sym_FindExactSymbol(symbolName);
if (!symbol)
if (!symbol) {
symbol = createsymbol(symbolName);
else if (sym_IsDefined(symbol)) {
} else if (sym_IsDefined(symbol)) {
error("'%s' already defined at ", symbolName);
dumpFilename(symbol);
putc('\n', stderr);
@@ -417,7 +410,7 @@ struct Symbol *sym_AddString(char const *symName, char const *value)
*/
struct Symbol *sym_AddSet(char const *symName, int32_t value)
{
struct Symbol *sym = findsymbol(symName, NULL);
struct Symbol *sym = sym_FindExactSymbol(symName);
if (sym == NULL) {
sym = createsymbol(symName);
@@ -426,8 +419,8 @@ struct Symbol *sym_AddSet(char const *symName, int32_t value)
symName, sym->type == SYM_LABEL ? "label" : "constant");
dumpFilename(sym);
putc('\n', stderr);
return sym;
} else {
/* TODO: can the scope be incorrect when taking over refs? */
updateSymbolFilename(sym);
}
@@ -445,7 +438,7 @@ struct Symbol *sym_AddSet(char const *symName, int32_t value)
static struct Symbol *addLabel(char const *name)
{
assert(name[0] != '.'); /* The symbol name must have been expanded prior */
struct Symbol *sym = findsymbol(name, NULL); /* Due to this, don't look for expansions */
struct Symbol *sym = sym_FindExactSymbol(name);
if (!sym) {
sym = createsymbol(name);
@@ -527,7 +520,7 @@ struct Symbol *sym_AddLabel(char const *name)
*/
void sym_Export(char const *symName)
{
struct Symbol *sym = sym_FindSymbol(symName);
struct Symbol *sym = sym_FindScopedSymbol(symName);
/* If the symbol doesn't exist, create a ref that can be purged */
if (!sym)
@@ -561,7 +554,7 @@ struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body,
*/
struct Symbol *sym_Ref(char const *symName)
{
struct Symbol *nsym = sym_FindSymbol(symName);
struct Symbol *nsym = sym_FindScopedSymbol(symName);
if (nsym == NULL) {
char fullname[MAXSYMLEN + 1];

View File

@@ -69,7 +69,7 @@ size_t readUTF8Char(uint8_t *dest, char const *src)
size_t i = 0;
for (;;) {
if (decode(&state, &codep, (uint8_t)src[i]) == 1)
if (decode(&state, &codep, src[i]) == 1)
fatalerror("invalid UTF-8 character\n");
dest[i] = src[i];

View File

@@ -36,6 +36,7 @@ static enum WarningState const defaultWarnings[NB_WARNINGS] = {
[WARNING_EMPTY_ENTRY] = WARNING_DISABLED,
[WARNING_LARGE_CONSTANT] = WARNING_DISABLED,
[WARNING_LONG_STR] = WARNING_DISABLED,
[WARNING_NESTED_COMMENT] = WARNING_ENABLED,
[WARNING_OBSOLETE] = WARNING_ENABLED,
[WARNING_SHIFT] = WARNING_DISABLED,
[WARNING_SHIFT_AMOUNT] = WARNING_DISABLED,
@@ -75,6 +76,7 @@ static char const *warningFlags[NB_WARNINGS_ALL] = {
"empty-entry",
"large-constant",
"long-string",
"nested-comment",
"obsolete",
"shift",
"shift-amount",
@@ -104,6 +106,7 @@ static uint8_t const _wallCommands[] = {
/* Warnings that are less likely to indicate an error */
static uint8_t const _wextraCommands[] = {
WARNING_EMPTY_ENTRY,
WARNING_NESTED_COMMENT,
META_WARNING_DONE
};
@@ -115,6 +118,7 @@ static uint8_t const _weverythingCommands[] = {
WARNING_EMPTY_ENTRY,
WARNING_LARGE_CONSTANT,
WARNING_LONG_STR,
WARNING_NESTED_COMMENT,
WARNING_OBSOLETE,
WARNING_SHIFT,
WARNING_SHIFT_AMOUNT,
@@ -218,7 +222,7 @@ void error(const char *fmt, ...)
nbErrors++;
}
noreturn_ void fatalerror(const char *fmt, ...)
_Noreturn void fatalerror(const char *fmt, ...)
{
va_list args;
@@ -246,7 +250,7 @@ void warning(enum WarningID id, char const *fmt, ...)
return;
case WARNING_DEFAULT:
trap_;
unreachable_();
/* Not reached */
case WARNING_ENABLED:

8
src/extern/err.c vendored
View File

@@ -34,7 +34,7 @@ void rgbds_vwarnx(const char *fmt, va_list ap)
putc('\n', stderr);
}
noreturn_ void rgbds_verr(int status, const char *fmt, va_list ap)
_Noreturn void rgbds_verr(int status, const char *fmt, va_list ap)
{
fprintf(stderr, "error: ");
if (fmt) {
@@ -46,7 +46,7 @@ noreturn_ void rgbds_verr(int status, const char *fmt, va_list ap)
exit(status);
}
noreturn_ void rgbds_verrx(int status, const char *fmt, va_list ap)
_Noreturn void rgbds_verrx(int status, const char *fmt, va_list ap)
{
fprintf(stderr, "error");
if (fmt) {
@@ -75,7 +75,7 @@ void rgbds_warnx(const char *fmt, ...)
va_end(ap);
}
noreturn_ void rgbds_err(int status, const char *fmt, ...)
_Noreturn void rgbds_err(int status, const char *fmt, ...)
{
va_list ap;
@@ -84,7 +84,7 @@ noreturn_ void rgbds_err(int status, const char *fmt, ...)
va_end(ap);
}
noreturn_ void rgbds_errx(int status, const char *fmt, ...)
_Noreturn void rgbds_errx(int status, const char *fmt, ...)
{
va_list ap;

View File

@@ -38,7 +38,7 @@ static const uint8_t utf8d[] = {
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* s8 */
};
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte)
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte)
{
uint32_t type = utf8d[byte];

View File

@@ -22,12 +22,10 @@ as destination can omit the destination as it is assumed to be register
.Sy A
by default.
The following two lines have the same effect:
.Pp
.Bd -literal -offset indent
OR A,B
OR B
.Ed
.Pp
.Sh LEGEND
List of abbreviations used in this document.
.Bl -tag

View File

@@ -26,7 +26,7 @@
The
.Nm
program converts PNG images into the Nintendo Game Boy's planar tile format.
.Pp
The resulting colors and their palette indices are determined differently depending on the input PNG file:
.Bl -dash -width Ds
.It
@@ -39,7 +39,7 @@ If the image has multiple shades that map to the same index, the palette is inst
.It
If the image has color (or the grayscale method failed), the colors are sorted from lightest to darkest.
.El
.Pp
The input image may not contain more colors than the selected bit depth allows.
Transparent pixels are set to palette index 0.
.Sh ARGUMENTS

View File

@@ -64,6 +64,22 @@ bool hash_AddElement(HashMap map, char const *key, void *element)
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)
{
HashType hashedKey = hash(key);

View File

@@ -439,7 +439,7 @@ void assign_AssignSections(void)
return;
}
trap_;
unreachable_();
}
void assign_Cleanup(void)

View File

@@ -13,6 +13,7 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -99,7 +100,7 @@ void error(struct FileStackNode const *where, uint32_t lineNo, char const *fmt,
nbErrors++;
}
noreturn_ void fatal(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
_Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo, char const *fmt, ...)
{
va_list ap;
@@ -126,7 +127,13 @@ FILE *openFile(char const *fileName, char const *mode)
if (!fileName)
return NULL;
FILE *file = fopen(fileName, mode);
FILE *file;
if (strcmp(fileName, "-") != 0)
file = fopen(fileName, mode);
else if (mode[0] == 'r')
file = fdopen(0, mode);
else
file = fdopen(1, mode);
if (!file)
err(1, "Could not open file \"%s\"", fileName);

View File

@@ -497,7 +497,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID)
if (!nodes[fileID].nodes)
err(1, "Failed to get memory for %s's nodes", fileName);
verbosePrint("Reading %u nodes...\n", nodes[fileID].nbNodes);
for (uint32_t i = 0; i < nodes[fileID].nbNodes; i++)
for (uint32_t i = nodes[fileID].nbNodes; i--; )
readFileStackNode(file, nodes[fileID].nodes, i, fileName);
/* This file's symbols, kept to link sections to them */

View File

@@ -116,7 +116,7 @@ option!
.Sh EXAMPLES
All you need for a basic ROM is an object file, which can be made into a ROM image like so:
.Pp
.D1 $ rgblink -o bar.gb foo.o
.Dl $ rgblink -o bar.gb foo.o
.Pp
The resulting
.Ar bar.gb
@@ -126,12 +126,10 @@ You should use
to fix these so that the program will actually run in a Game Boy:
.Pp
.Dl $ rgbfix -v bar.gb
.Ed
.Pp
Here is a more complete example:
.Pp
.Dl $ rgblink -o bin/game.gb -n bin/game.sym -p 0xFF obj/title.o obj/engine.o
.Ed
.Sh BUGS
Please report bugs on
.Lk https://github.com/gbdev/rgbds/issues GitHub .

View File

@@ -19,7 +19,6 @@ They can be lowercase or uppercase, it is ignored.
Any line can contain a comment starting with
.Ql \&;
that ends at the end of the line:
.Pp
.Bd -literal -offset indent
ROMX $F ; This is a comment
"Functions to read array"
@@ -86,6 +85,6 @@ in the linker script.
.Sh HISTORY
.Nm
was originally written by Carsten S\(/orensen as part of the ASMotor package,
and was later packaged in RGBDS by Justin Lloyd. It is now maintained by a
number of contributors at
and was later packaged in RGBDS by Justin Lloyd.
It is now maintained by a number of contributors at
.Lk https://github.com/gbdev/rgbds .

View File

@@ -318,7 +318,7 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg,
{
switch (command) {
case COMMAND_INVALID:
trap_;
unreachable_();
case COMMAND_ORG:
break;
@@ -331,8 +331,8 @@ static void processCommand(enum LinkerScriptCommand command, uint16_t arg,
}
if (arg < *pc)
errx(1, "%s(%" PRIu32 "): `%s` cannot be used to go backwards",
linkerScriptName, lineNo, commands[command]);
errx(1, "%s(%" PRIu32 "): `%s` cannot be used to go backwards (currently at $%x)",
linkerScriptName, lineNo, commands[command], *pc);
*pc = arg;
}
@@ -391,12 +391,12 @@ struct SectionPlacement *script_NextSection(void)
switch (parserState) {
case PARSER_FIRSTTIME:
trap_;
unreachable_();
case PARSER_LINESTART:
switch (token->type) {
case TOKEN_INVALID:
trap_;
unreachable_();
case TOKEN_EOF:
if (!popFile())

View File

@@ -108,7 +108,7 @@ static void mergeSections(struct Section *target, struct Section *other, enum Se
break;
case SECTION_NORMAL:
trap_;
unreachable_();
}
other->nextu = target->nextu;

View File

@@ -18,7 +18,6 @@ and
.Xr rgblink 1 .
.Em Please note that the specifications may change .
This toolchain is in development and new features may require adding more information to the current format, or modifying some fields, which would break compatibility with older versions.
.Pp
.Sh FILE STRUCTURE
The following types are used:
.Pp
@@ -29,7 +28,6 @@ is an 8bit integer.
.Ar STRING
is a 0terminated string of
.Ar BYTE .
.Pp
.Bd -literal
; Header
@@ -219,8 +217,7 @@ The
In the RGB format, RPN expressions are stored as
.Ar BYTE Ns s
with some bytes being special prefixes for integers and symbols.
.Pp
.Bl -column -offset indent ".Sy String" ".Sy String"
.Bl -column -offset indent "Sy String" "Sy String"
.It Sy Value Ta Sy Meaning
.It Li $00 Ta Li + operator
.It Li $01 Ta Li - operator
@@ -259,7 +256,6 @@ integer follows.
.It Li $81 Ta Ar LONG
symbol ID follows.
.El
.Pp
.Sh SEE ALSO
.Xr rgbasm 1 ,
.Xr rgblink 1 ,

View File

@@ -13,7 +13,6 @@
.Nd Rednex Game Boy Development System
.Sh EXAMPLES
To get a working ROM image from a single assembly source file:
.Pp
.Bd -literal -offset indent
$ rgbasm \-o bar.o foo.asm
$ rgblink \-o baz.gb bar.o
@@ -26,7 +25,7 @@ $ rgbfix \-v \-p 0 baz.gb
.Xr rgbds 5 ,
.Xr gbz80 7
.Sh HISTORY
.Bl -ohang
.Bl -item
.It
1997, Carsten S\(/orensen (AKA SurfSmurf) writes ASMotor as a general-purpose
assembler/linker system for DOS/Win32.
@@ -37,8 +36,8 @@ assembly/machine code, and releases this version as RGBDS.
2009, Vegard Nossum adapts the code to be more UNIX-like and releases this
version as rgbds-linux on GitHub.
.It
2010, Anthony J. Bentley forks that repository. The fork becomes the reference
implementation of rgbds.
2010, Anthony J. Bentley forks that repository.
The fork becomes the reference implementation of rgbds.
.It
2017, Bentley's repository is moved to a neutral name.
It is now maintained by a number of contributors at

View File

@@ -0,0 +1 @@
align 1

View File

@@ -0,0 +1,2 @@
FATAL: align-pc-outside-section.asm(1):
Code generation before SECTION directive

View File

View File

@@ -0,0 +1,2 @@
/* block comments containing /* throw warnings */
PRINTT "reachable\n"

View File

@@ -0,0 +1,2 @@
warning: block-comment-contents-error.asm(1): [-Wnested-comment]
/* in block comment

View File

@@ -0,0 +1 @@
reachable

View File

@@ -0,0 +1 @@
PRINTT /* block comments must terminate before EOF

View File

@@ -0,0 +1,5 @@
ERROR: block-comment-termination-error.asm(1):
Unterminated block comment
ERROR: block-comment-termination-error.asm(1):
syntax error
error: Assembly aborted (2 errors)!

View File

@@ -0,0 +1,5 @@
PRINTT /* block comments are ignored // ** */ "hi\n"
PRINTT "block (/* ... */) comments at ends of line are fine\n" /* hi */
PRINTT /* block comments
can span multiple lines
*/ "mutliline\n"

View File

View File

@@ -0,0 +1,3 @@
hi
block (/* ... */) comments at ends of line are fine
mutliline

View File

@@ -0,0 +1,23 @@
SECTION "test", ROM0
newcharmap foo
charmap "<START>", $00
charmap "<RAM>", $01
charmap "<WAIT>", $02
charmap "<ASM>", $03
charmap "<NUM>", $04
charmap "<EXIT>", $05
charmap "<SOUND>", $06
charmap "<DAY>", $07
charmap "<FAR>", $08
; At this point, enough nodes were allocated for 'foo' to be reallocated.
; Its value in the charmaps' hashmap should have been updated too,
; so that usages of 'foo' will not segfault.
; This uses 'foo; by switching to it.
setcharmap foo
; This uses 'foo' by deriving another charmap from it.
newcharmap bar, foo

View File

View File

5
test/asm/empty-local.asm Normal file
View File

@@ -0,0 +1,5 @@
SECTION "Test", ROM0
Label:
Label.:

0
test/asm/empty-local.err Normal file
View File

0
test/asm/empty-local.out Normal file
View File

View File

@@ -0,0 +1,3 @@
DEFINE equs "mac: MACRO\nPRINTT \"Hello :D\\n\"\nENDM"
DEFINE
mac

View File

View File

@@ -0,0 +1 @@
Hello :D

View File

@@ -0,0 +1,5 @@
; This test tries to pass invalid UTF-8 through a macro argument
; to exercise the lexer's reportGarbageChar
m:MACRO \1
ENDM
m <EFBFBD><EFBFBD>

View File

@@ -0,0 +1,5 @@
ERROR: invalid-utf-8.asm(4) -> invalid-utf-8.asm::m(3):
Unknown character 0xCF
ERROR: invalid-utf-8.asm(4) -> invalid-utf-8.asm::m(3):
Unknown character 0xD3
error: Assembly aborted (2 errors)!

View File

View File

@@ -27,3 +27,10 @@ X EQUS "{X7E}"
X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X+X
x: db 0
; this tests long RPN expressions being used as the RHS, as this once triggered
; a realloc bug
db 1+(x+X)
; likewise, a long symbol could result in an insufficient *initial* allocation
db A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000+0+0

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

View File

@@ -0,0 +1,27 @@
outer_ok: MACRO
definition equs "inner_ok: MACRO\nPRINTT \"Hello!\\n\"\nENDM"
definition
PURGE definition
ENDM
outer_ok
inner_ok
outer_arg: MACRO
definition equs "inner_arg: MACRO\nPRINTT \"outer: \1\\ninner: \\1\\n\"\nENDM"
definition
PURGE definition
ENDM
outer_arg outside
inner_arg inside
outer: MACRO
WARN "Nested macros shouldn't work, whose argument would be \\1?"
inner: MACRO
ENDM
outer
inner

View File

@@ -0,0 +1,5 @@
warning: nested-macrodef.asm(26) -> nested-macrodef.asm::outer(22): [-Wuser]
Nested macros shouldn't work, whose argument would be \1?
ERROR: nested-macrodef.asm(26) -> nested-macrodef.asm::outer(25):
Unterminated macro definition
error: Assembly aborted (1 errors)!

View File

@@ -0,0 +1,3 @@
Hello!
outer: outside
inner: inside

View File

@@ -0,0 +1,4 @@
m: MACRO
shift -3
ENDM
m

View File

@@ -0,0 +1,3 @@
ERROR: shift-negative.asm(4) -> shift-negative.asm::m(2):
Cannot shift arguments by negative amount -3
error: Assembly aborted (1 errors)!

View File

View File

@@ -0,0 +1,2 @@
shift
shift 3

View File

@@ -0,0 +1,5 @@
ERROR: shift-outside-macro.asm(1):
Cannot shift macro arguments outside of a macro
ERROR: shift-outside-macro.asm(2):
Cannot shift macro arguments outside of a macro
error: Assembly aborted (2 errors)!

View File

View File

@@ -0,0 +1,3 @@
lab:
PRINTV lab-lab
PRINTT "\n"

View File

@@ -0,0 +1,5 @@
ERROR: use-label-outside-section.asm(1):
Label "lab" created outside of a SECTION
ERROR: use-label-outside-section.asm(2):
Expected constant expression: 'lab' is not constant at assembly time
error: Assembly aborted (2 errors)!

View File

@@ -0,0 +1 @@
$0

View File

@@ -1 +1 @@
RGBDS version 0.4.1
RGBDS version 0.4.2

View File

@@ -0,0 +1,2 @@
PRINTT /* // PRINTT "this is **comm //ented out\n" */ "this is not commented out\n"
PRINTT /*//*/ "this is not commented out\n"

View File

@@ -0,0 +1,2 @@
warning: weird-comments.asm(2): [-Wnested-comment]
/* in block comment

View File

@@ -0,0 +1,2 @@
this is not commented out
this is not commented out