mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Add support for toggleable warnings
This commit is contained in:
1
Makefile
1
Makefile
@@ -66,6 +66,7 @@ rgbasm_obj := \
|
||||
src/asm/rpn.o \
|
||||
src/asm/symbol.o \
|
||||
src/asm/util.o \
|
||||
src/asm/warning.o \
|
||||
src/extern/err.o \
|
||||
src/extern/getopt.o \
|
||||
src/extern/utf8decoder.o \
|
||||
|
||||
@@ -40,29 +40,6 @@ void opt_Push(void);
|
||||
void opt_Pop(void);
|
||||
void opt_Parse(char *s);
|
||||
|
||||
/*
|
||||
* Used for errors that compromise the whole assembly process by affecting the
|
||||
* folliwing code, potencially making the assembler generate errors caused by
|
||||
* the first one and unrelated to the code that the assembler complains about.
|
||||
* 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, ...);
|
||||
|
||||
/*
|
||||
* Used for errors that make it impossible to assemble correctly, but don't
|
||||
* affect the following code. The code will fail to assemble but the user will
|
||||
* get a list of all errors at the end, making it easier to fix all of them at
|
||||
* once.
|
||||
*/
|
||||
void yyerror(const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* Used to warn the user about problems that don't prevent the generation of
|
||||
* valid code.
|
||||
*/
|
||||
void warning(const char *fmt, ...);
|
||||
|
||||
#define YY_FATAL_ERROR fatalerror
|
||||
|
||||
#ifdef YYLMAX
|
||||
|
||||
52
include/asm/warning.h
Normal file
52
include/asm/warning.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef WARNING_H
|
||||
#define WARNING_H
|
||||
|
||||
extern unsigned int nbErrors;
|
||||
|
||||
enum WarningID {
|
||||
WARNING_USER,
|
||||
WARNING_OBSOLETE,
|
||||
WARNING_BUILTIN_ARG,
|
||||
WARNING_LARGE_CONSTANT,
|
||||
WARNING_SHIFT,
|
||||
WARNING_DIV,
|
||||
WARNING_EMPTY_ENTRY,
|
||||
WARNING_LONG_STR,
|
||||
|
||||
NB_WARNINGS,
|
||||
|
||||
/* Warnings past this point are "meta" warnings */
|
||||
WARNING_ALL = NB_WARNINGS,
|
||||
WARNING_EXTRA,
|
||||
WARNING_EVERYTHING,
|
||||
|
||||
NB_WARNINGS_ALL
|
||||
#define NB_META_WARNINGS (NB_WARNINGS_ALL - NB_WARNINGS)
|
||||
};
|
||||
|
||||
void processWarningFlag(char const *flag);
|
||||
|
||||
/*
|
||||
* Used to warn the user about problems that don't prevent the generation of
|
||||
* valid code.
|
||||
*/
|
||||
void warning(enum WarningID id, const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* Used for errors that compromise the whole assembly process by affecting the
|
||||
* following code, potencially making the assembler generate errors caused by
|
||||
* the first one and unrelated to the code that the assembler complains about.
|
||||
* 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, ...);
|
||||
|
||||
/*
|
||||
* Used for errors that make it impossible to assemble correctly, but don't
|
||||
* affect the following code. The code will fail to assemble but the user will
|
||||
* get a list of all errors at the end, making it easier to fix all of them at
|
||||
* once.
|
||||
*/
|
||||
void yyerror(const char *fmt, ...);
|
||||
|
||||
#endif
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "asm/rpn.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/util.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/utf8decoder.h"
|
||||
|
||||
@@ -482,7 +483,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||
uint32_t curLen = 0;
|
||||
|
||||
if (pos < 1) {
|
||||
warning("STRSUB: Position starts at 1");
|
||||
warning(WARNING_BUILTIN_ARG, "STRSUB: Position starts at 1");
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
@@ -500,7 +501,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||
}
|
||||
|
||||
if (!src[srcIndex])
|
||||
warning("STRSUB: Position %lu is past the end of the string",
|
||||
warning(WARNING_BUILTIN_ARG, "STRSUB: Position %lu is past the end of the string",
|
||||
(unsigned long)pos);
|
||||
|
||||
/* Copy from source to destination. */
|
||||
@@ -517,7 +518,7 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
|
||||
}
|
||||
|
||||
if (curLen < len)
|
||||
warning("STRSUB: Length too big: %lu", (unsigned long)len);
|
||||
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %lu", (unsigned long)len);
|
||||
|
||||
/* Check for partial code point. */
|
||||
if (state != 0)
|
||||
@@ -807,7 +808,7 @@ pushs : T_POP_PUSHS { out_PushSection(); }
|
||||
fail : T_POP_FAIL string { fatalerror("%s", $2); }
|
||||
;
|
||||
|
||||
warn : T_POP_WARN string { warning("%s", $2); }
|
||||
warn : T_POP_WARN string { warning(WARNING_USER, "%s", $2); }
|
||||
;
|
||||
|
||||
shift : T_POP_SHIFT { sym_ShiftCurrentMacroArgs(); }
|
||||
@@ -905,7 +906,7 @@ ds : T_POP_DS uconst
|
||||
|
||||
db : T_POP_DB constlist_8bit_entry comma constlist_8bit {
|
||||
if (nListCountEmpty > 0) {
|
||||
warning("Empty entry in list of 8-bit elements (treated as 0).");
|
||||
warning(WARNING_EMPTY_ENTRY, "Empty entry in list of 8-bit elements (treated as 0).");
|
||||
}
|
||||
}
|
||||
| T_POP_DB constlist_8bit_entry
|
||||
@@ -913,7 +914,7 @@ db : T_POP_DB constlist_8bit_entry comma constlist_8bit {
|
||||
|
||||
dw : T_POP_DW constlist_16bit_entry comma constlist_16bit {
|
||||
if (nListCountEmpty > 0) {
|
||||
warning("Empty entry in list of 16-bit elements (treated as 0).");
|
||||
warning(WARNING_EMPTY_ENTRY, "Empty entry in list of 16-bit elements (treated as 0).");
|
||||
}
|
||||
}
|
||||
| T_POP_DW constlist_16bit_entry
|
||||
@@ -921,7 +922,7 @@ dw : T_POP_DW constlist_16bit_entry comma constlist_16bit {
|
||||
|
||||
dl : T_POP_DL constlist_32bit_entry comma constlist_32bit {
|
||||
if (nListCountEmpty > 0) {
|
||||
warning("Empty entry in list of 32-bit elements (treated as 0).");
|
||||
warning(WARNING_EMPTY_ENTRY, "Empty entry in list of 32-bit elements (treated as 0).");
|
||||
}
|
||||
}
|
||||
| T_POP_DL constlist_32bit_entry
|
||||
@@ -957,7 +958,7 @@ import_list_entry : T_ID
|
||||
* This is done automatically if the label isn't found
|
||||
* in the list of defined symbols.
|
||||
*/
|
||||
warning("IMPORT is a deprecated keyword with no effect: %s", $1);
|
||||
warning(WARNING_OBSOLETE, "IMPORT is a deprecated keyword with no effect: %s", $1);
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1461,7 +1462,7 @@ const : T_ID { constexpr_Symbol(&$$, $1); }
|
||||
string : T_STRING
|
||||
{
|
||||
if (snprintf($$, MAXSTRLEN + 1, "%s", $1) > MAXSTRLEN)
|
||||
warning("String is too long '%s'", $1);
|
||||
warning(WARNING_LONG_STR, "String is too long '%s'", $1);
|
||||
}
|
||||
| T_OP_STRSUB '(' string comma uconst comma uconst ')'
|
||||
{
|
||||
@@ -1470,19 +1471,19 @@ string : T_STRING
|
||||
| T_OP_STRCAT '(' string comma string ')'
|
||||
{
|
||||
if (snprintf($$, MAXSTRLEN + 1, "%s%s", $3, $5) > MAXSTRLEN)
|
||||
warning("STRCAT: String too long '%s%s'", $3, $5);
|
||||
warning(WARNING_LONG_STR, "STRCAT: String too long '%s%s'", $3, $5);
|
||||
}
|
||||
| T_OP_STRUPR '(' string ')'
|
||||
{
|
||||
if (snprintf($$, MAXSTRLEN + 1, "%s", $3) > MAXSTRLEN)
|
||||
warning("STRUPR: String too long '%s'", $3);
|
||||
warning(WARNING_LONG_STR, "STRUPR: String too long '%s'", $3);
|
||||
|
||||
upperstring($$);
|
||||
}
|
||||
| T_OP_STRLWR '(' string ')'
|
||||
{
|
||||
if (snprintf($$, MAXSTRLEN + 1, "%s", $3) > MAXSTRLEN)
|
||||
warning("STRUPR: String too long '%s'", $3);
|
||||
warning(WARNING_LONG_STR, "STRUPR: String too long '%s'", $3);
|
||||
|
||||
lowerstring($$);
|
||||
}
|
||||
@@ -1533,22 +1534,22 @@ sectiontype : T_SECT_WRAM0 { $$ = SECTTYPE_WRAM0; }
|
||||
| T_SECT_OAM { $$ = SECTTYPE_OAM; }
|
||||
| T_SECT_HOME
|
||||
{
|
||||
warning("HOME section name is deprecated, use ROM0 instead.");
|
||||
warning(WARNING_OBSOLETE, "HOME section name is deprecated, use ROM0 instead.");
|
||||
$$ = SECTTYPE_ROM0;
|
||||
}
|
||||
| T_SECT_DATA
|
||||
{
|
||||
warning("DATA section name is deprecated, use ROMX instead.");
|
||||
warning(WARNING_OBSOLETE, "DATA section name is deprecated, use ROMX instead.");
|
||||
$$ = SECTTYPE_ROMX;
|
||||
}
|
||||
| T_SECT_CODE
|
||||
{
|
||||
warning("CODE section name is deprecated, use ROMX instead.");
|
||||
warning(WARNING_OBSOLETE, "CODE section name is deprecated, use ROMX instead.");
|
||||
$$ = SECTTYPE_ROMX;
|
||||
}
|
||||
| T_SECT_BSS
|
||||
{
|
||||
warning("BSS section name is deprecated, use WRAM0 instead.");
|
||||
warning(WARNING_OBSOLETE, "BSS section name is deprecated, use WRAM0 instead.");
|
||||
$$ = SECTTYPE_WRAM0;
|
||||
}
|
||||
;
|
||||
@@ -1746,7 +1747,7 @@ z80_jp : T_Z80_JP const_16bit
|
||||
| T_Z80_JP T_MODE_HL_IND
|
||||
{
|
||||
out_AbsByte(0xE9);
|
||||
warning("'JP [HL]' is obsolete, use 'JP HL' instead.");
|
||||
warning(WARNING_OBSOLETE, "'JP [HL]' is obsolete, use 'JP HL' instead.");
|
||||
}
|
||||
| T_Z80_JP T_MODE_HL
|
||||
{
|
||||
@@ -1773,7 +1774,7 @@ z80_ldi : T_Z80_LDI T_MODE_HL_IND comma T_MODE_A
|
||||
| T_Z80_LDI T_MODE_A comma T_MODE_HL
|
||||
{
|
||||
out_AbsByte(0x0A | (2 << 4));
|
||||
warning("'LDI A,HL' is obsolete, use 'LDI A,[HL]' or 'LD A,[HL+] instead.");
|
||||
warning(WARNING_OBSOLETE, "'LDI A,HL' is obsolete, use 'LDI A,[HL]' or 'LD A,[HL+] instead.");
|
||||
}
|
||||
| T_Z80_LDI T_MODE_A comma T_MODE_HL_IND
|
||||
{
|
||||
@@ -1788,7 +1789,7 @@ z80_ldd : T_Z80_LDD T_MODE_HL_IND comma T_MODE_A
|
||||
| T_Z80_LDD T_MODE_A comma T_MODE_HL
|
||||
{
|
||||
out_AbsByte(0x0A | (3 << 4));
|
||||
warning("'LDD A,HL' is obsolete, use 'LDD A,[HL]' or 'LD A,[HL-] instead.");
|
||||
warning(WARNING_OBSOLETE, "'LDD A,HL' is obsolete, use 'LDD A,[HL]' or 'LD A,[HL-] instead.");
|
||||
}
|
||||
| T_Z80_LDD T_MODE_A comma T_MODE_HL_IND
|
||||
{
|
||||
@@ -1842,7 +1843,7 @@ z80_ld_hl : T_Z80_LD T_MODE_HL comma '[' T_MODE_SP const_8bit ']'
|
||||
{
|
||||
out_AbsByte(0xF8);
|
||||
out_RelByte(&$6);
|
||||
warning("'LD HL,[SP+e8]' is obsolete, use 'LD HL,SP+e8' instead.");
|
||||
warning(WARNING_OBSOLETE, "'LD HL,[SP+e8]' is obsolete, use 'LD HL,SP+e8' instead.");
|
||||
}
|
||||
| T_Z80_LD T_MODE_HL comma T_MODE_SP const_8bit
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "asm/main.h"
|
||||
#include "asm/output.h"
|
||||
#include "asm/util.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#define CHARMAP_HASH_SIZE (1 << 9)
|
||||
|
||||
@@ -39,7 +40,7 @@ static void warnSectionCharmap(void)
|
||||
if (warned)
|
||||
return;
|
||||
|
||||
warning("Using 'charmap' within a section when the current charmap is 'main' is deprecated");
|
||||
warning(WARNING_OBSOLETE, "Using 'charmap' within a section when the current charmap is 'main' is deprecated");
|
||||
warned = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "asm/mymath.h"
|
||||
#include "asm/rpn.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "asmy.h"
|
||||
|
||||
@@ -171,7 +172,7 @@ void constexpr_BinaryOp(struct ConstExpression *expr,
|
||||
break;
|
||||
case T_OP_SHL:
|
||||
if (value1 < 0)
|
||||
warning("Left shift of negative value: %d",
|
||||
warning(WARNING_SHIFT, "Left shift of negative value: %d",
|
||||
value1);
|
||||
|
||||
if (value2 < 0)
|
||||
@@ -200,7 +201,7 @@ void constexpr_BinaryOp(struct ConstExpression *expr,
|
||||
if (value2 == 0)
|
||||
fatalerror("Division by zero");
|
||||
if (value1 == INT32_MIN && value2 == -1) {
|
||||
warning("Division of min value by -1");
|
||||
warning(WARNING_DIV, "Division of min value by -1");
|
||||
result = INT32_MIN;
|
||||
} else {
|
||||
result = value1 / value2;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "asm/main.h"
|
||||
#include "asm/output.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
|
||||
@@ -291,7 +292,7 @@ void fstk_DumpToStr(char *buf, size_t buflen)
|
||||
len -= retcode;
|
||||
|
||||
if (!len)
|
||||
warning("File stack dump too long, got truncated");
|
||||
warning(WARNING_LONG_STR, "File stack dump too long, got truncated");
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "asm/rpn.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
@@ -126,7 +127,7 @@ static int32_t ascii2bin(char *s)
|
||||
* the Game Boy tile width, produces a nonsensical result.
|
||||
*/
|
||||
if (size > 8) {
|
||||
warning("Graphics constant '%s' is too long",
|
||||
warning(WARNING_LARGE_CONSTANT, "Graphics constant '%s' is too long",
|
||||
start);
|
||||
}
|
||||
} else {
|
||||
@@ -143,7 +144,7 @@ static int32_t ascii2bin(char *s)
|
||||
}
|
||||
|
||||
if (overflow)
|
||||
warning("Integer constant '%s' is too large",
|
||||
warning(WARNING_LARGE_CONSTANT, "Integer constant '%s' is too large",
|
||||
start);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "asm/lexer.h"
|
||||
#include "asm/main.h"
|
||||
#include "asm/rpn.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "asm/output.h"
|
||||
#include "asm/main.h"
|
||||
#include "asm/charmap.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
#include "extern/getopt.h"
|
||||
@@ -38,7 +39,7 @@ char **cldefines;
|
||||
|
||||
clock_t nStartClock, nEndClock;
|
||||
int32_t nLineNo;
|
||||
uint32_t nTotalLines, nPC, nIFDepth, nUnionDepth, nErrors;
|
||||
uint32_t nTotalLines, nPC, nIFDepth, nUnionDepth;
|
||||
bool skipElif;
|
||||
uint32_t unionStart[128], unionSize[128];
|
||||
|
||||
@@ -234,61 +235,8 @@ static void opt_ParseDefines(void)
|
||||
sym_AddString(cldefines[i], cldefines[i + 1]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Error handling
|
||||
*/
|
||||
void verror(const char *fmt, va_list args)
|
||||
{
|
||||
fputs("ERROR: ", stderr);
|
||||
fstk_Dump();
|
||||
fputs(":\n ", stderr);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fputc('\n', stderr);
|
||||
fstk_DumpStringExpansions();
|
||||
nErrors++;
|
||||
}
|
||||
|
||||
void yyerror(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
verror(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
noreturn_ void fatalerror(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
verror(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
exit(5);
|
||||
}
|
||||
|
||||
void warning(const char *fmt, ...)
|
||||
{
|
||||
if (!CurrentOptions.warnings)
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
fputs("warning: ", stderr);
|
||||
fstk_Dump();
|
||||
fputs(":\n ", stderr);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fputc('\n', stderr);
|
||||
fstk_DumpStringExpansions();
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Short options */
|
||||
static char const *optstring = "b:D:Eg:hi:LM:o:p:r:Vvw";
|
||||
static char const *optstring = "b:D:Eg:hi:LM:o:p:r:VvW:w";
|
||||
|
||||
/*
|
||||
* Equivalent long options
|
||||
@@ -314,7 +262,7 @@ static struct option const longopts[] = {
|
||||
{ "recursion-depth", required_argument, NULL, 'r' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "warning", no_argument, NULL, 'w' },
|
||||
{ "warning", required_argument, NULL, 'W' },
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -323,7 +271,7 @@ static void print_usage(void)
|
||||
printf(
|
||||
"usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
|
||||
" [-M dependfile] [-o outfile] [-p pad_value]\n"
|
||||
" [-r recursion_depth] file.asm\n");
|
||||
" [-r recursion_depth] [-W warning] [-w] file.asm\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -436,6 +384,9 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
newopt.verbose = true;
|
||||
break;
|
||||
case 'W':
|
||||
processWarningFlag(optarg);
|
||||
break;
|
||||
case 'w':
|
||||
newopt.warnings = false;
|
||||
break;
|
||||
@@ -476,7 +427,6 @@ int main(int argc, char *argv[])
|
||||
skipElif = true;
|
||||
nUnionDepth = 0;
|
||||
nPC = 0;
|
||||
nErrors = 0;
|
||||
sym_Init();
|
||||
sym_SetExportAll(CurrentOptions.exportall);
|
||||
fstk_Init(tzMainfile);
|
||||
@@ -486,8 +436,8 @@ int main(int argc, char *argv[])
|
||||
yy_set_state(LEX_STATE_NORMAL);
|
||||
opt_SetCurrentOptions(&DefaultOptions);
|
||||
|
||||
if (yyparse() != 0 || nErrors != 0)
|
||||
errx(1, "Assembly aborted (%ld errors)!", nErrors);
|
||||
if (yyparse() != 0 || nbErrors != 0)
|
||||
errx(1, "Assembly aborted (%ld errors)!", nbErrors);
|
||||
|
||||
if (nIFDepth != 0)
|
||||
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "asm/output.h"
|
||||
#include "asm/rpn.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "asm/main.h"
|
||||
#include "asm/rpn.h"
|
||||
#include "asm/symbol.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
@@ -396,7 +397,8 @@ void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
||||
|
||||
if (!expr->isReloc) {
|
||||
if (src1->nVal < 0)
|
||||
warning("Left shift of negative value: %d", src1->nVal);
|
||||
warning(WARNING_SHIFT, "Left shift of negative value: %d",
|
||||
src1->nVal);
|
||||
|
||||
if (src2->nVal < 0)
|
||||
fatalerror("Shift by negative value: %d", src2->nVal);
|
||||
@@ -447,7 +449,7 @@ void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
||||
fatalerror("Division by zero");
|
||||
|
||||
if (src1->nVal == INT32_MIN && src2->nVal == -1) {
|
||||
warning("Division of min value by -1");
|
||||
warning(WARNING_DIV, "Division of min value by -1");
|
||||
expr->nVal = INT32_MIN;
|
||||
} else {
|
||||
expr->nVal = (src1->nVal / src2->nVal);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "asm/mymath.h"
|
||||
#include "asm/output.h"
|
||||
#include "asm/util.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
|
||||
@@ -133,7 +134,7 @@ struct sSymbol *createsymbol(char *s)
|
||||
}
|
||||
|
||||
if (snprintf((*ppsym)->tzName, MAXSYMLEN + 1, "%s", s) > MAXSYMLEN)
|
||||
warning("Symbol name is too long: '%s'", s);
|
||||
warning(WARNING_LONG_STR, "Symbol name is too long: '%s'", s);
|
||||
|
||||
(*ppsym)->nValue = 0;
|
||||
(*ppsym)->nType = 0;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "asm/main.h"
|
||||
#include "asm/util.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/utf8decoder.h"
|
||||
|
||||
|
||||
240
src/asm/warning.c
Normal file
240
src/asm/warning.c
Normal file
@@ -0,0 +1,240 @@
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asm/fstack.h"
|
||||
#include "asm/main.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "extern/err.h"
|
||||
|
||||
unsigned int nbErrors = 0;
|
||||
|
||||
enum WarningState {
|
||||
WARNING_DEFAULT,
|
||||
WARNING_DISABLED,
|
||||
WARNING_ENABLED,
|
||||
WARNING_ERROR
|
||||
};
|
||||
|
||||
static enum WarningState const defaultWarnings[NB_WARNINGS] = {
|
||||
WARNING_ENABLED, /* User warnings */
|
||||
WARNING_DISABLED, /* Obsolete things */
|
||||
WARNING_DISABLED, /* Invalid args to builtins */
|
||||
WARNING_DISABLED, /* Constants too large */
|
||||
WARNING_DISABLED, /* Shifting undefined behavior */
|
||||
WARNING_DISABLED, /* Division undefined behavior */
|
||||
WARNING_DISABLED, /* Empty entry in `db`, `dw` or `dl` */
|
||||
WARNING_DISABLED, /* String too long for internal buffers */
|
||||
};
|
||||
|
||||
static enum WarningState warningStates[NB_WARNINGS];
|
||||
|
||||
static bool warningsAreErrors; /* Set if `-Werror` was specified */
|
||||
|
||||
static enum WarningState warningState(enum WarningID id)
|
||||
{
|
||||
/* Check if warnings are globally disabled */
|
||||
if (!CurrentOptions.warnings)
|
||||
return WARNING_DISABLED;
|
||||
|
||||
/* Get the actual state */
|
||||
enum WarningState state = warningStates[id];
|
||||
|
||||
if (state == WARNING_DEFAULT)
|
||||
/* The state isn't set, grab its default state */
|
||||
state = defaultWarnings[id];
|
||||
|
||||
if (warningsAreErrors && state == WARNING_ENABLED)
|
||||
state = WARNING_ERROR;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static char const *warningFlags[NB_WARNINGS_ALL] = {
|
||||
"user",
|
||||
"obsolete",
|
||||
"builtin-args",
|
||||
"large-constant",
|
||||
"shift",
|
||||
"div",
|
||||
"empty-entry",
|
||||
"long-string",
|
||||
|
||||
/* Meta warnings */
|
||||
"all",
|
||||
"extra",
|
||||
"everything" /* Especially useful for testing */
|
||||
};
|
||||
|
||||
enum MetaWarningCommand {
|
||||
META_WARNING_DONE = NB_WARNINGS
|
||||
};
|
||||
|
||||
/* Warnings that probably indicate an error */
|
||||
static uint8_t const _wallCommands[] = {
|
||||
WARNING_USER,
|
||||
WARNING_BUILTIN_ARG,
|
||||
WARNING_LARGE_CONSTANT,
|
||||
WARNING_EMPTY_ENTRY,
|
||||
WARNING_LONG_STR,
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
/* Warnings that are less likely to indicate an error */
|
||||
static uint8_t const _wextraCommands[] = {
|
||||
WARNING_OBSOLETE,
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
/* Literally everything. Notably useful for testing */
|
||||
static uint8_t const _weverythingCommands[] = {
|
||||
WARNING_USER,
|
||||
WARNING_OBSOLETE,
|
||||
WARNING_BUILTIN_ARG,
|
||||
WARNING_LARGE_CONSTANT,
|
||||
WARNING_SHIFT,
|
||||
WARNING_DIV,
|
||||
WARNING_EMPTY_ENTRY,
|
||||
WARNING_LONG_STR,
|
||||
META_WARNING_DONE
|
||||
};
|
||||
|
||||
static uint8_t const *metaWarningCommands[NB_META_WARNINGS] = {
|
||||
_wallCommands,
|
||||
_wextraCommands,
|
||||
_weverythingCommands
|
||||
};
|
||||
|
||||
void processWarningFlag(char const *flag)
|
||||
{
|
||||
static bool setError = false;
|
||||
|
||||
/* First, try to match against a "meta" warning */
|
||||
for (enum WarningID id = NB_WARNINGS; id < NB_WARNINGS_ALL; id++) {
|
||||
/* TODO: improve the matching performance? */
|
||||
if (!strcmp(flag, warningFlags[id])) {
|
||||
/* We got a match! */
|
||||
uint8_t const *ptr =
|
||||
metaWarningCommands[id - NB_WARNINGS];
|
||||
|
||||
for (;;) {
|
||||
if (*ptr == META_WARNING_DONE)
|
||||
return;
|
||||
|
||||
/* Warning flag, set without override */
|
||||
if (warningStates[*ptr] == WARNING_DEFAULT)
|
||||
warningStates[*ptr] = WARNING_ENABLED;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's not a meta warning, specially check against `-Werror` */
|
||||
if (!strncmp(flag, "error", strlen("error"))) {
|
||||
char const *errorFlag = flag + strlen("error");
|
||||
|
||||
switch (*errorFlag) {
|
||||
case '\0':
|
||||
/* `-Werror` */
|
||||
warningsAreErrors = true;
|
||||
return;
|
||||
|
||||
case '=':
|
||||
/* `-Werror=XXX */
|
||||
setError = true;
|
||||
processWarningFlag(errorFlag + 1); /* Skip the `=` */
|
||||
setError = false;
|
||||
return;
|
||||
|
||||
/* Otherwise, allow parsing as another flag */
|
||||
}
|
||||
}
|
||||
|
||||
/* Well, it's either a normal warning or a mistake */
|
||||
|
||||
/* Check if this is a negation */
|
||||
bool isNegation = !strncmp(flag, "no-", strlen("no-")) && !setError;
|
||||
char const *rootFlag = isNegation ? flag + strlen("no-") : flag;
|
||||
enum WarningState state = setError ? WARNING_ERROR :
|
||||
isNegation ? WARNING_DISABLED : WARNING_ENABLED;
|
||||
|
||||
/* Try to match the flag against a "normal" flag */
|
||||
for (enum WarningID id = 0; id < NB_WARNINGS; id++) {
|
||||
if (!strcmp(rootFlag, warningFlags[id])) {
|
||||
/* We got a match! */
|
||||
warningStates[id] = state;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
warnx("Unknown warning `%s`", flag);
|
||||
}
|
||||
|
||||
void verror(const char *fmt, va_list args, char const *flag)
|
||||
{
|
||||
fputs("ERROR: ", stderr);
|
||||
fstk_Dump();
|
||||
fprintf(stderr, flag ? ": [-Werror=%s]\n " : ":\n ", flag);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fputc('\n', stderr);
|
||||
fstk_DumpStringExpansions();
|
||||
nbErrors++;
|
||||
}
|
||||
|
||||
void yyerror(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
verror(fmt, args, NULL);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
noreturn_ void fatalerror(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
verror(fmt, args, NULL);
|
||||
va_end(args);
|
||||
|
||||
exit(5);
|
||||
}
|
||||
|
||||
void warning(enum WarningID id, char const *fmt, ...)
|
||||
{
|
||||
char const *flag = warningFlags[id];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
switch (warningState(id)) {
|
||||
case WARNING_DISABLED:
|
||||
return;
|
||||
|
||||
case WARNING_ERROR:
|
||||
verror(fmt, args, flag);
|
||||
va_end(args);
|
||||
return;
|
||||
|
||||
case WARNING_DEFAULT:
|
||||
abort();
|
||||
/* Not reached */
|
||||
|
||||
case WARNING_ENABLED:
|
||||
break;
|
||||
}
|
||||
|
||||
fputs("warning: ", stderr);
|
||||
fstk_Dump();
|
||||
fprintf(stderr, ": [-W%s]\n ", flag);
|
||||
vfprintf(stderr, fmt, args);
|
||||
fputc('\n', stderr);
|
||||
fstk_DumpStringExpansions();
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
warning: correct-line-number.asm(5):
|
||||
warning: correct-line-number.asm(5): [-Wuser]
|
||||
Am I geting ahead of myself?
|
||||
warning: correct-line-number.asm(11):
|
||||
warning: correct-line-number.asm(11): [-Wuser]
|
||||
Hopefully not.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
warning: multiple-charmaps.asm(75):
|
||||
warning: multiple-charmaps.asm(75): [-Wobsolete]
|
||||
Using 'charmap' within a section when the current charmap is 'main' is deprecated
|
||||
ERROR: multiple-charmaps.asm(100) -> multiple-charmaps.asm::new_(7):
|
||||
Charmap 'map1' already exists
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
warning: overflow.asm(24):
|
||||
warning: overflow.asm(24): [-Wdiv]
|
||||
Division of min value by -1
|
||||
warning: overflow.asm(25):
|
||||
warning: overflow.asm(25): [-Wdiv]
|
||||
Division of min value by -1
|
||||
warning: overflow.asm(34):
|
||||
warning: overflow.asm(34): [-Wshift]
|
||||
Left shift of negative value: -1
|
||||
warning: overflow.asm(35):
|
||||
warning: overflow.asm(35): [-Wshift]
|
||||
Left shift of negative value: -1
|
||||
warning: overflow.asm(39):
|
||||
warning: overflow.asm(39): [-Wlarge-constant]
|
||||
Integer constant '4294967296' is too large
|
||||
warning: overflow.asm(42):
|
||||
warning: overflow.asm(42): [-Wlarge-constant]
|
||||
Graphics constant '`333333333' is too long
|
||||
$80000000
|
||||
$7FFFFFFF
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
warning: strsub.asm(13) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(13) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Length too big: 32
|
||||
warning: strsub.asm(14) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(14) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Length too big: 300
|
||||
warning: strsub.asm(15) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(15) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Position starts at 1
|
||||
warning: strsub.asm(15) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(15) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Length too big: 300
|
||||
warning: strsub.asm(16) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(16) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Position 4 is past the end of the string
|
||||
warning: strsub.asm(17) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(17) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Position 4 is past the end of the string
|
||||
warning: strsub.asm(17) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(17) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Length too big: 1
|
||||
warning: strsub.asm(20) -> strsub.asm::xstrsub(4):
|
||||
warning: strsub.asm(20) -> strsub.asm::xstrsub(4): [-Wbuiltin-args]
|
||||
STRSUB: Length too big: 10
|
||||
A
|
||||
B
|
||||
|
||||
@@ -10,7 +10,7 @@ rc=0
|
||||
for i in *.asm; do
|
||||
for variant in '' '.pipe'; do
|
||||
if [ -z "$variant" ]; then
|
||||
../../rgbasm -o $o $i > $after 2>&1
|
||||
../../rgbasm -Weverything -o $o $i > $after 2>&1
|
||||
desired_output=${i%.asm}.out
|
||||
else
|
||||
# `include-recursion.asm` refers to its own name inside the test code.
|
||||
@@ -23,7 +23,7 @@ for i in *.asm; do
|
||||
# stdin redirection makes the input an unseekable pipe - a scenario
|
||||
# that's harder to deal with and was broken when the feature was
|
||||
# first implemented.
|
||||
cat $i | ../../rgbasm -o $o - > $after 2>&1
|
||||
cat $i | ../../rgbasm -Weverything -o $o - > $after 2>&1
|
||||
|
||||
# Escape regex metacharacters
|
||||
desired_output=$before
|
||||
|
||||
Reference in New Issue
Block a user