Axe the constexpr expression evaluator

This avoids redundancy between them (and also having to port fixes and features)
The error messages have been preserved through a string reporting mechanism
This commit is contained in:
ISSOtm
2020-01-20 23:12:41 +01:00
parent 52d62c6b21
commit 1d78cd0f03
12 changed files with 101 additions and 500 deletions

View File

@@ -54,7 +54,6 @@ all: rgbasm rgblink rgbfix rgbgfx
rgbasm_obj := \ rgbasm_obj := \
src/asm/asmy.o \ src/asm/asmy.o \
src/asm/charmap.o \ src/asm/charmap.o \
src/asm/constexpr.o \
src/asm/fstack.o \ src/asm/fstack.o \
src/asm/globlex.o \ src/asm/globlex.o \
src/asm/lexer.o \ src/asm/lexer.o \

View File

@@ -1,35 +0,0 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#ifndef RGBDS_ASM_CONSTEXPR_H
#define RGBDS_ASM_CONSTEXPR_H
#include <stdint.h>
struct ConstExpression {
union {
int32_t nVal;
struct sSymbol *pSym;
} u;
uint32_t isSym;
};
void constexpr_Symbol(struct ConstExpression *expr, char *tzSym);
void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym);
void constexpr_BankSection(struct ConstExpression *expr, char *tzSym);
void constexpr_Number(struct ConstExpression *expr, int32_t i);
void constexpr_UnaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src);
void constexpr_BinaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src1,
const struct ConstExpression *src2);
int32_t constexpr_GetConstantValue(struct ConstExpression *expr);
#endif /* RGBDS_ASM_CONSTEXPR_H */

View File

@@ -19,6 +19,7 @@
struct Expression { struct Expression {
bool isKnown; // Whether the expression's value is known bool isKnown; // Whether the expression's value is known
int32_t nVal; // If the expression's value is known, it's here int32_t nVal; // If the expression's value is known, it's here
char *reason; // Why the expression is not known, if it isn't
uint8_t *tRPN; // Array of bytes serializing the RPN expression uint8_t *tRPN; // Array of bytes serializing the RPN expression
uint32_t nRPNCapacity; // Size of the `tRPN` buffer uint32_t nRPNCapacity; // Size of the `tRPN` buffer
uint32_t nRPNLength; // Used size of the `tRPN` buffer uint32_t nRPNLength; // Used size of the `tRPN` buffer

View File

@@ -18,7 +18,6 @@
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/charmap.h" #include "asm/charmap.h"
#include "asm/constexpr.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/main.h" #include "asm/main.h"
@@ -510,11 +509,10 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len)
char tzString[MAXSTRLEN + 1]; char tzString[MAXSTRLEN + 1];
struct Expression sVal; struct Expression sVal;
int32_t nConstValue; int32_t nConstValue;
struct ConstExpression sConstExpr;
} }
%type <sVal> relocconst %type <sVal> relocconst
%type <sConstExpr> const %type <nConstValue> const
%type <nConstValue> uconst %type <nConstValue> uconst
%type <nConstValue> const_3bit %type <nConstValue> const_3bit
%type <sVal> const_8bit %type <sVal> const_8bit
@@ -966,17 +964,17 @@ global_list_entry : T_ID
equ : T_LABEL T_POP_EQU const equ : T_LABEL T_POP_EQU const
{ {
sym_AddEqu($1, constexpr_GetConstantValue(&$3)); sym_AddEqu($1, $3);
} }
; ;
set : T_LABEL T_POP_SET const set : T_LABEL T_POP_SET const
{ {
sym_AddSet($1, constexpr_GetConstantValue(&$3)); sym_AddSet($1, $3);
} }
| T_LABEL T_POP_EQUAL const | T_LABEL T_POP_EQUAL const
{ {
sym_AddSet($1, constexpr_GetConstantValue(&$3)); sym_AddSet($1, $3);
} }
; ;
@@ -1004,12 +1002,10 @@ incbin : T_POP_INCBIN string
charmap : T_POP_CHARMAP string comma const charmap : T_POP_CHARMAP string comma const
{ {
int32_t value = constexpr_GetConstantValue(&$4); if (($4 & 0xFF) != $4)
if ((value & 0xFF) != value)
warning(WARNING_TRUNCATION, "Expression must be 8-bit"); warning(WARNING_TRUNCATION, "Expression must be 8-bit");
if (charmap_Add($2, value & 0xFF) == -1) if (charmap_Add($2, $4 & 0xFF) == -1)
yyerror("Error parsing charmap. Either you've added too many (%i), or the input character length is too long (%i)' : %s\n", MAXCHARMAPS, CHARMAPLENGTH, strerror(errno)); yyerror("Error parsing charmap. Either you've added too many (%i), or the input character length is too long (%i)' : %s\n", MAXCHARMAPS, CHARMAPLENGTH, strerror(errno));
} }
; ;
@@ -1044,26 +1040,26 @@ printt : T_POP_PRINTT string
printv : T_POP_PRINTV const printv : T_POP_PRINTV const
{ {
printf("$%X", constexpr_GetConstantValue(&$2)); printf("$%X", $2);
} }
; ;
printi : T_POP_PRINTI const printi : T_POP_PRINTI const
{ {
printf("%d", constexpr_GetConstantValue(&$2)); printf("%d", $2);
} }
; ;
printf : T_POP_PRINTF const printf : T_POP_PRINTF const
{ {
math_Print(constexpr_GetConstantValue(&$2)); math_Print($2);
} }
; ;
if : T_POP_IF const if : T_POP_IF const
{ {
nIFDepth++; nIFDepth++;
if (!constexpr_GetConstantValue(&$2)) { if (!$2) {
/* /*
* Continue parsing after ELSE, or at ELIF or * Continue parsing after ELSE, or at ELIF or
* ENDC keyword. * ENDC keyword.
@@ -1095,7 +1091,7 @@ elif : T_POP_ELIF const
*/ */
skipElif = true; skipElif = true;
if (!constexpr_GetConstantValue(&$2)) { if (!$2) {
/* /*
* Continue parsing after ELSE, or at * Continue parsing after ELSE, or at
* ELIF or ENDC keyword. * ELIF or ENDC keyword.
@@ -1127,7 +1123,7 @@ endc : T_POP_ENDC
const_3bit : const const_3bit : const
{ {
int32_t value = constexpr_GetConstantValue(&$1); int32_t value = $1;
if ((value < 0) || (value > 7)) if ((value < 0) || (value > 7))
yyerror("Immediate value must be 3-bit"); yyerror("Immediate value must be 3-bit");
else else
@@ -1268,57 +1264,57 @@ relocconst : T_ID
} }
| T_OP_ROUND '(' const ')' | T_OP_ROUND '(' const ')'
{ {
rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_Round($3));
} }
| T_OP_CEIL '(' const ')' | T_OP_CEIL '(' const ')'
{ {
rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_Ceil($3));
} }
| T_OP_FLOOR '(' const ')' | T_OP_FLOOR '(' const ')'
{ {
rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_Floor($3));
} }
| T_OP_FDIV '(' const comma const ')' | T_OP_FDIV '(' const comma const ')'
{ {
rpn_Number(&$$, rpn_Number(&$$,
math_Div(constexpr_GetConstantValue(&$3), math_Div($3,
constexpr_GetConstantValue(&$5))); $5));
} }
| T_OP_FMUL '(' const comma const ')' | T_OP_FMUL '(' const comma const ')'
{ {
rpn_Number(&$$, rpn_Number(&$$,
math_Mul(constexpr_GetConstantValue(&$3), math_Mul($3,
constexpr_GetConstantValue(&$5))); $5));
} }
| T_OP_SIN '(' const ')' | T_OP_SIN '(' const ')'
{ {
rpn_Number(&$$, math_Sin(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_Sin($3));
} }
| T_OP_COS '(' const ')' | T_OP_COS '(' const ')'
{ {
rpn_Number(&$$, math_Cos(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_Cos($3));
} }
| T_OP_TAN '(' const ')' | T_OP_TAN '(' const ')'
{ {
rpn_Number(&$$, math_Tan(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_Tan($3));
} }
| T_OP_ASIN '(' const ')' | T_OP_ASIN '(' const ')'
{ {
rpn_Number(&$$, math_ASin(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_ASin($3));
} }
| T_OP_ACOS '(' const ')' | T_OP_ACOS '(' const ')'
{ {
rpn_Number(&$$, math_ACos(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_ACos($3));
} }
| T_OP_ATAN '(' const ')' | T_OP_ATAN '(' const ')'
{ {
rpn_Number(&$$, math_ATan(constexpr_GetConstantValue(&$3))); rpn_Number(&$$, math_ATan($3));
} }
| T_OP_ATAN2 '(' const comma const ')' | T_OP_ATAN2 '(' const comma const ')'
{ {
rpn_Number(&$$, rpn_Number(&$$,
math_ATan2(constexpr_GetConstantValue(&$3), math_ATan2($3,
constexpr_GetConstantValue(&$5))); $5));
} }
| T_OP_STRCMP '(' string comma string ')' | T_OP_STRCMP '(' string comma string ')'
{ {
@@ -1339,92 +1335,23 @@ relocconst : T_ID
uconst : const uconst : const
{ {
int32_t value = constexpr_GetConstantValue(&$1); int32_t value = $1;
if (value < 0) if (value < 0)
fatalerror("Constant mustn't be negative: %d", value); fatalerror("Constant mustn't be negative: %d", value);
$$ = value; $$ = value;
} }
; ;
const : T_ID { constexpr_Symbol(&$$, $1); } const : relocconst
| T_NUMBER { constexpr_Number(&$$, $1); }
| T_OP_HIGH '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_LOW '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_BANK '(' T_ID ')'
{ {
constexpr_BankSymbol(&$$, $3); if (!rpn_isKnown(&$1)) {
yyerror("Expected constant expression: %s",
$1.reason);
$$ = 0;
} else {
$$ = $1.nVal;
} }
| T_OP_BANK '(' string ')'
{
constexpr_BankSection(&$$, $3);
} }
| string
{
char *s = $1;
int32_t length = charmap_Convert(&s);
constexpr_Number(&$$, str2int2(s, length));
free(s);
}
| T_OP_LOGICNOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| const T_OP_LOGICOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICAND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICEQU const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICGT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICLT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICGE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICLE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_LOGICNE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_ADD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_SUB const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_XOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_OR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_AND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_SHL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_SHR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_MUL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_DIV const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| const T_OP_MOD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
| T_OP_ADD const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| T_OP_SUB const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| T_OP_NOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
| T_OP_ROUND '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_CEIL '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_FLOOR '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_FDIV '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
| T_OP_FMUL '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
| T_OP_SIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_COS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_TAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ASIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ACOS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ATAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
| T_OP_ATAN2 '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
| T_OP_DEF {
oDontExpandStrings = true;
} '(' T_ID ')'
{
struct sSymbol const *sym = sym_FindSymbol($4);
if (sym && !(sym_IsDefined(sym) && sym->type != SYM_LABEL))
yyerror("Label \"%s\" is not a valid argument to DEF",
$4);
constexpr_Number(&$$, !!sym);
oDontExpandStrings = false;
}
| T_OP_STRCMP '(' string comma string ')'
{
constexpr_Number(&$$, strcmp($3, $5));
}
| T_OP_STRIN '(' string comma string ')'
{
char *p = strstr($3, $5);
if (p != NULL)
constexpr_Number(&$$, p - $3 + 1);
else
constexpr_Number(&$$, 0);
}
| T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlenUTF8($3)); }
| '(' const ')' { $$ = $2; }
; ;
string : T_STRING string : T_STRING

View File

@@ -1,298 +0,0 @@
/*
* This file is part of RGBDS.
*
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
*
* SPDX-License-Identifier: MIT
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "asm/asm.h"
#include "asm/constexpr.h"
#include "asm/lexer.h"
#include "asm/main.h"
#include "asm/mymath.h"
#include "asm/output.h"
#include "asm/rpn.h"
#include "asm/symbol.h"
#include "asm/warning.h"
#include "asmy.h"
void constexpr_Symbol(struct ConstExpression *expr, char *tzSym)
{
struct sSymbol *sym = sym_FindSymbol(tzSym);
if (!sym) {
fatalerror("'%s' not defined", tzSym);
} else if (!sym_IsConstant(sym)) {
expr->u.pSym = sym;
expr->isSym = 1;
} else {
constexpr_Number(expr, sym_GetConstantValue(tzSym));
}
}
void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym)
{
constexpr_Number(expr, 0);
struct sSymbol *sym = sym_FindSymbol(tzSym);
if (!sym) {
yyerror("BANK argument doesn't exist");
} else if (sym == pPCSymbol) {
if (pCurrentSection->nBank == -1)
yyerror("Current bank is not known yet");
else
constexpr_Number(expr, pCurrentSection->nBank);
} else if (sym->type != SYM_LABEL) {
yyerror("BANK argument must be a label");
} else if (sym->pSection->nBank == -1) {
yyerror("BANK argument's bank is not known yet'");
} else {
constexpr_Number(expr, sym->pSection->nBank);
}
}
void constexpr_BankSection(struct ConstExpression *expr, char *tzSectionName)
{
constexpr_Number(expr, 0);
struct Section *pSection = out_FindSectionByName(tzSectionName);
if (!pSection)
yyerror("Section \"%s\" doesn't exist", tzSectionName);
else if (pSection->nBank == -1)
yyerror("Section \"%s\"'s bank is not known yet",
tzSectionName);
else
constexpr_Number(expr, pSection->nBank);
}
void constexpr_Number(struct ConstExpression *expr, int32_t i)
{
expr->u.nVal = i;
expr->isSym = 0;
}
void constexpr_UnaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src)
{
if (src->isSym)
fatalerror("Non-constant operand in constant expression");
int32_t value = src->u.nVal;
int32_t result = 0;
switch (op) {
case T_OP_HIGH:
result = (value >> 8) & 0xFF;
break;
case T_OP_LOW:
result = value & 0xFF;
break;
case T_OP_LOGICNOT:
result = !value;
break;
case T_OP_ADD:
result = value;
break;
case T_OP_SUB:
result = -(uint32_t)value;
break;
case T_OP_NOT:
result = ~value;
break;
case T_OP_ROUND:
result = math_Round(value);
break;
case T_OP_CEIL:
result = math_Ceil(value);
break;
case T_OP_FLOOR:
result = math_Floor(value);
break;
case T_OP_SIN:
result = math_Sin(value);
break;
case T_OP_COS:
result = math_Cos(value);
break;
case T_OP_TAN:
result = math_Tan(value);
break;
case T_OP_ASIN:
result = math_ASin(value);
break;
case T_OP_ACOS:
result = math_ACos(value);
break;
case T_OP_ATAN:
result = math_ATan(value);
break;
default:
fatalerror("Unknown unary op");
}
constexpr_Number(expr, result);
}
void constexpr_BinaryOp(struct ConstExpression *expr,
int32_t op,
const struct ConstExpression *src1,
const struct ConstExpression *src2)
{
int32_t value1;
int32_t value2;
int32_t result = 0;
if (op == T_OP_SUB && src1->isSym && src2->isSym) {
char *symName1 = src1->u.pSym->tzName;
char *symName2 = src2->u.pSym->tzName;
if (!sym_IsRelocDiffDefined(symName1, symName2))
fatalerror("'%s - %s' not defined", symName1, symName2);
value1 = sym_GetDefinedValue(symName1);
value2 = sym_GetDefinedValue(symName2);
result = value1 - value2;
} else if (src1->isSym || src2->isSym) {
fatalerror("Non-constant operand in constant expression");
} else {
value1 = src1->u.nVal;
value2 = src2->u.nVal;
switch (op) {
case T_OP_LOGICOR:
result = value1 || value2;
break;
case T_OP_LOGICAND:
result = value1 && value2;
break;
case T_OP_LOGICEQU:
result = value1 == value2;
break;
case T_OP_LOGICGT:
result = value1 > value2;
break;
case T_OP_LOGICLT:
result = value1 < value2;
break;
case T_OP_LOGICGE:
result = value1 >= value2;
break;
case T_OP_LOGICLE:
result = value1 <= value2;
break;
case T_OP_LOGICNE:
result = value1 != value2;
break;
case T_OP_ADD:
result = (uint32_t)value1 + (uint32_t)value2;
break;
case T_OP_SUB:
result = (uint32_t)value1 - (uint32_t)value2;
break;
case T_OP_XOR:
result = value1 ^ value2;
break;
case T_OP_OR:
result = value1 | value2;
break;
case T_OP_AND:
result = value1 & value2;
break;
case T_OP_SHL:
case T_OP_SHR:
if (value2 < 0)
warning(WARNING_SHIFT_AMOUNT, "Shifting %s by negative amount %d",
op == T_OP_SHL ? "left" : "right",
value2);
if (op == T_OP_SHR) {
value2 = -value2; /* Right shift == neg left */
if (value1 < 0)
warning(WARNING_SHIFT, "Shifting negative value %d",
value1);
}
if (value2 >= 0) {
// Shift left
if (value2 >= 32) {
warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %d",
value2);
result = 0;
} else {
/*
* Use unsigned to force a bitwise shift
* Casting back is OK because the types
* implement two's complement behavior
*/
result = (uint32_t)value1 << value2;
}
} else {
// Shift right
value2 = -value2;
if (value2 >= 32) {
warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %d",
value2);
result = value1 < 0 ? -1 : 0;
} else if (value1 >= 0) {
result = value1 >> value2;
} else {
/*
* The C standard leaves shifting right
* negative values undefined, so use a
* left shift manually sign-extended
*/
result = (uint32_t)value1 >> value2 |
-((uint32_t)1 << (32 - value2));
}
}
break;
case T_OP_MUL:
result = (uint32_t)value1 * (uint32_t)value2;
break;
case T_OP_DIV:
if (value2 == 0)
fatalerror("Division by zero");
if (value1 == INT32_MIN && value2 == -1) {
warning(WARNING_DIV, "Division of min value by -1");
result = INT32_MIN;
} else {
result = value1 / value2;
}
break;
case T_OP_MOD:
if (value2 == 0)
fatalerror("Division by zero");
if (value1 == INT32_MIN && value2 == -1)
result = 0;
else
result = value1 % value2;
break;
case T_OP_FDIV:
result = math_Div(value1, value2);
break;
case T_OP_FMUL:
result = math_Mul(value1, value2);
break;
case T_OP_ATAN2:
result = math_ATan2(value1, value2);
break;
default:
fatalerror("Unknown binary op");
}
}
constexpr_Number(expr, result);
}
int32_t constexpr_GetConstantValue(struct ConstExpression *expr)
{
if (expr->isSym)
fatalerror("Non-constant expression");
return expr->u.nVal;
}

View File

@@ -14,7 +14,6 @@
#include <string.h> #include <string.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/constexpr.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/main.h" #include "asm/main.h"
#include "asm/rpn.h" #include "asm/rpn.h"

View File

@@ -15,7 +15,6 @@
#include <ctype.h> #include <ctype.h>
#include "asm/asm.h" #include "asm/asm.h"
#include "asm/constexpr.h"
#include "asm/fstack.h" #include "asm/fstack.h"
#include "asm/lexer.h" #include "asm/lexer.h"
#include "asm/main.h" #include "asm/main.h"

View File

@@ -23,6 +23,21 @@
#include "asm/output.h" #include "asm/output.h"
#include "asm/warning.h" #include "asm/warning.h"
/* Makes an expression "not known", also setting its error message */
#define makeUnknown(expr_, ...) do { \
struct Expression *_expr = expr_; \
_expr->isKnown = false; \
/* If we had `asprintf` this would be great, but alas. */ \
_expr->reason = malloc(128); /* Use an initial reasonable size */ \
if (!_expr->reason) \
fatalerror("Can't allocate err string: %s", strerror(errno)); \
int size = snprintf(_expr->reason, 128, __VA_ARGS__); \
if (size >= 128) { /* If this wasn't enough, try again */ \
_expr->reason = realloc(_expr->reason, size + 1); \
sprintf(_expr->reason, __VA_ARGS__); \
} \
} while (0)
static uint8_t *reserveSpace(struct Expression *expr, uint32_t size) static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
{ {
/* This assumes the RPN length is always less than the capacity */ /* This assumes the RPN length is always less than the capacity */
@@ -65,6 +80,7 @@ void rpn_Init(struct Expression *expr)
expr->nRPNPatchSize = 0; expr->nRPNPatchSize = 0;
expr->nRPNOut = 0; expr->nRPNOut = 0;
expr->isKnown = true; expr->isKnown = true;
expr->reason = NULL;
} }
/* /*
@@ -73,6 +89,7 @@ void rpn_Init(struct Expression *expr)
void rpn_Free(struct Expression *expr) void rpn_Free(struct Expression *expr)
{ {
free(expr->tRPN); free(expr->tRPN);
free(expr->reason);
rpn_Init(expr); rpn_Init(expr);
} }
@@ -111,7 +128,7 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
if (!sym || !sym_IsConstant(sym)) { if (!sym || !sym_IsConstant(sym)) {
rpn_Init(expr); rpn_Init(expr);
sym_Ref(tzSym); sym_Ref(tzSym);
expr->isKnown = false; makeUnknown(expr, "'%s' is not defined", tzSym);
expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */
size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */
@@ -136,7 +153,7 @@ void rpn_BankSelf(struct Expression *expr)
rpn_Init(expr); rpn_Init(expr);
if (pCurrentSection->nBank == -1) if (pCurrentSection->nBank == -1)
expr->isKnown = false; makeUnknown(expr, "Current section's bank is not known");
else else
expr->nVal = pCurrentSection->nBank; expr->nVal = pCurrentSection->nBank;
@@ -173,7 +190,7 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym)
/* Symbol's section is known and bank is fixed */ /* Symbol's section is known and bank is fixed */
expr->nVal = pSymbol->pSection->nBank; expr->nVal = pSymbol->pSection->nBank;
else else
expr->isKnown = false; makeUnknown(expr, "\"%s\"'s bank is not known", tzSym);
} }
} }
@@ -186,7 +203,8 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName)
if (pSection && pSection->nBank != -1) if (pSection && pSection->nBank != -1)
expr->nVal = pSection->nBank; expr->nVal = pSection->nBank;
else else
expr->isKnown = false; makeUnknown(expr, "Section \"%s\"'s bank is not known",
tzSectionName);
size_t nameLen = strlen(tzSectionName) + 1; /* Don't forget NUL! */ size_t nameLen = strlen(tzSectionName) + 1; /* Don't forget NUL! */
uint8_t *ptr = reserveSpace(expr, nameLen + 1); uint8_t *ptr = reserveSpace(expr, nameLen + 1);
@@ -234,9 +252,6 @@ void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
static int32_t shift(int32_t shiftee, int32_t amount) static int32_t shift(int32_t shiftee, int32_t amount)
{ {
if (shiftee < 0)
warning(WARNING_SHIFT, "Shifting negative value %d", shiftee);
if (amount >= 0) { if (amount >= 0) {
// Left shift // Left shift
if (amount >= 32) { if (amount >= 32) {
@@ -346,28 +361,27 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
expr->nVal = src1->nVal & src2->nVal; expr->nVal = src1->nVal & src2->nVal;
break; break;
case RPN_SHL: case RPN_SHL:
if (expr->isKnown) {
if (src2->nVal < 0) if (src2->nVal < 0)
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d", warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %d",
src2->nVal); src2->nVal);
expr->nVal = shift(src1->nVal, src2->nVal); expr->nVal = shift(src1->nVal, src2->nVal);
}
break; break;
case RPN_SHR: case RPN_SHR:
if (expr->isKnown) { if (src1->nVal < 0)
warning(WARNING_SHIFT, "Shifting negative value %d",
src1->nVal);
if (src2->nVal < 0) if (src2->nVal < 0)
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d", warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %d",
src2->nVal); src2->nVal);
expr->nVal = shift(src1->nVal, -src2->nVal); expr->nVal = shift(src1->nVal, -src2->nVal);
}
break; break;
case RPN_MUL: case RPN_MUL:
expr->nVal = uleft * uright; expr->nVal = uleft * uright;
break; break;
case RPN_DIV: case RPN_DIV:
if (expr->isKnown) {
if (src2->nVal == 0) if (src2->nVal == 0)
fatalerror("Division by zero"); fatalerror("Division by zero");
@@ -378,10 +392,8 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
} else { } else {
expr->nVal = src1->nVal / src2->nVal; expr->nVal = src1->nVal / src2->nVal;
} }
}
break; break;
case RPN_MOD: case RPN_MOD:
if (expr->isKnown) {
if (src2->nVal == 0) if (src2->nVal == 0)
fatalerror("Division by zero"); fatalerror("Division by zero");
@@ -389,7 +401,6 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
expr->nVal = 0; expr->nVal = 0;
else else
expr->nVal = src1->nVal % src2->nVal; expr->nVal = src1->nVal % src2->nVal;
}
break; break;
case RPN_UNSUB: case RPN_UNSUB:
@@ -425,12 +436,18 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
expr->nRPNLength = 0; expr->nRPNLength = 0;
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, memcpy(reserveSpace(expr, sizeof(bytes)), bytes,
sizeof(bytes)); sizeof(bytes));
/* Use the other expression's un-const reason */
expr->reason = src2->reason;
free(src1->reason);
} else { } else {
/* Otherwise just reuse its RPN buffer */ /* Otherwise just reuse its RPN buffer */
expr->nRPNPatchSize = src1->nRPNPatchSize; expr->nRPNPatchSize = src1->nRPNPatchSize;
expr->tRPN = src1->tRPN; expr->tRPN = src1->tRPN;
expr->nRPNCapacity = src1->nRPNCapacity; expr->nRPNCapacity = src1->nRPNCapacity;
expr->nRPNLength = src1->nRPNLength; expr->nRPNLength = src1->nRPNLength;
expr->reason = src1->reason;
free(src2->reason);
} }
/* Now, merge the right expression into the left one */ /* Now, merge the right expression into the left one */

View File

@@ -1,9 +1,9 @@
ERROR: bank.asm(14) -> bank.asm::def_sect(8): ERROR: bank.asm(14) -> bank.asm::def_sect(8):
Section "ROMX_bad"'s bank is not known yet Expected constant expression: Section "ROMX_bad"'s bank is not known
ERROR: bank.asm(16) -> bank.asm::def_sect(8): ERROR: bank.asm(16) -> bank.asm::def_sect(8):
Section "VRAM_bad"'s bank is not known yet Expected constant expression: Section "VRAM_bad"'s bank is not known
ERROR: bank.asm(18) -> bank.asm::def_sect(8): ERROR: bank.asm(18) -> bank.asm::def_sect(8):
Section "SRAM_bad"'s bank is not known yet Expected constant expression: Section "SRAM_bad"'s bank is not known
ERROR: bank.asm(21) -> bank.asm::def_sect(8): ERROR: bank.asm(21) -> bank.asm::def_sect(8):
Section "WRAMX_bad"'s bank is not known yet Expected constant expression: Section "WRAMX_bad"'s bank is not known
error: Assembly aborted (4 errors)! error: Assembly aborted (4 errors)!

View File

@@ -2,8 +2,6 @@ warning: overflow.asm(24): [-Wdiv]
Division of min value by -1 Division of min value by -1
warning: overflow.asm(25): [-Wdiv] warning: overflow.asm(25): [-Wdiv]
Division of min value by -1 Division of min value by -1
warning: overflow.asm(35): [-Wshift]
Shifting negative value -1
warning: overflow.asm(39): [-Wlarge-constant] warning: overflow.asm(39): [-Wlarge-constant]
Integer constant '4294967296' is too large Integer constant '4294967296' is too large
warning: overflow.asm(42): [-Wlarge-constant] warning: overflow.asm(42): [-Wlarge-constant]

View File

@@ -1,5 +1,5 @@
ERROR: pc-bank.asm(2): ERROR: pc-bank.asm(2):
Source address $2a00 not in $FF00 to $FFFF Source address $2a00 not in $FF00 to $FFFF
ERROR: pc-bank.asm(11): ERROR: pc-bank.asm(11):
Current bank is not known yet Expected constant expression: Current section's bank is not known
error: Assembly aborted (2 errors)! error: Assembly aborted (2 errors)!

View File

@@ -6,18 +6,12 @@ warning: shift.asm(14) -> shift.asm::test(3): [-Wshift-amount]
Shifting left by large amount 9001 Shifting left by large amount 9001
warning: shift.asm(14) -> shift.asm::test(6): [-Wshift-amount] warning: shift.asm(14) -> shift.asm::test(6): [-Wshift-amount]
Shifting left by large amount 9001 Shifting left by large amount 9001
warning: shift.asm(15) -> shift.asm::test(3): [-Wshift]
Shifting negative value -1
warning: shift.asm(16) -> shift.asm::test(3): [-Wshift]
Shifting negative value -1
warning: shift.asm(16) -> shift.asm::test(3): [-Wshift-amount] warning: shift.asm(16) -> shift.asm::test(3): [-Wshift-amount]
Shifting left by large amount 32 Shifting left by large amount 32
warning: shift.asm(16) -> shift.asm::test(6): [-Wshift-amount] warning: shift.asm(16) -> shift.asm::test(6): [-Wshift-amount]
Shifting left by large amount 32 Shifting left by large amount 32
warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount] warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount]
Shifting left by negative value: -9001 Shifting left by negative amount -9001
warning: shift.asm(17) -> shift.asm::test(3): [-Wshift]
Shifting negative value -1
warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount] warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount]
Shifting right by large amount 9001 Shifting right by large amount 9001
warning: shift.asm(17) -> shift.asm::test(6): [-Wshift-amount] warning: shift.asm(17) -> shift.asm::test(6): [-Wshift-amount]
@@ -52,15 +46,15 @@ warning: shift.asm(23) -> shift.asm::test(3): [-Wshift]
Shifting negative value -4 Shifting negative value -4
warning: shift.asm(23) -> shift.asm::test(6): [-Wshift] warning: shift.asm(23) -> shift.asm::test(6): [-Wshift]
Shifting negative value -4 Shifting negative value -4
warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount]
Shifting right by negative value: -9001
warning: shift.asm(24) -> shift.asm::test(3): [-Wshift] warning: shift.asm(24) -> shift.asm::test(3): [-Wshift]
Shifting negative value -1 Shifting negative value -1
warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount]
Shifting left by large amount 9001
warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount]
Shifting right by negative amount -9001 Shifting right by negative amount -9001
warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount]
Shifting left by large amount 9001
warning: shift.asm(24) -> shift.asm::test(6): [-Wshift] warning: shift.asm(24) -> shift.asm::test(6): [-Wshift]
Shifting negative value -1 Shifting negative value -1
warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount]
Shifting right by negative amount -9001
warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount]
Shifting left by large amount 9001 Shifting left by large amount 9001