mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Merge pull request #476 from ISSOtm/expr_cleanup
Clean up expression evaluation
This commit is contained in:
1
Makefile
1
Makefile
@@ -54,7 +54,6 @@ all: rgbasm rgblink rgbfix rgbgfx
|
||||
rgbasm_obj := \
|
||||
src/asm/asmy.o \
|
||||
src/asm/charmap.o \
|
||||
src/asm/constexpr.o \
|
||||
src/asm/fstack.o \
|
||||
src/asm/globlex.o \
|
||||
src/asm/lexer.o \
|
||||
|
||||
@@ -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 */
|
||||
@@ -10,62 +10,36 @@
|
||||
#define RGBDS_ASM_RPN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "linkdefs.h"
|
||||
|
||||
#define MAXRPNLEN 1048576
|
||||
|
||||
struct Expression {
|
||||
int32_t nVal;
|
||||
uint8_t *tRPN;
|
||||
uint32_t nRPNCapacity;
|
||||
uint32_t nRPNLength;
|
||||
uint32_t nRPNPatchSize;
|
||||
uint32_t nRPNOut;
|
||||
uint32_t isReloc;
|
||||
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
|
||||
bool isKnown; // Whether the expression's value is known
|
||||
bool isSymbol; // Whether the expression represents a symbol
|
||||
uint8_t *tRPN; // Array of bytes serializing the RPN expression
|
||||
uint32_t nRPNCapacity; // Size of the `tRPN` buffer
|
||||
uint32_t nRPNLength; // Used size of the `tRPN` buffer
|
||||
uint32_t nRPNPatchSize; // Size the expression will take in the obj file
|
||||
// FIXME: does this need to be part of the struct?
|
||||
uint32_t nRPNOut; // How many bytes have been written
|
||||
};
|
||||
|
||||
/* FIXME: Should be defined in `asmy.h`, but impossible with POSIX Yacc */
|
||||
extern int32_t nPCOffset;
|
||||
|
||||
uint32_t rpn_isReloc(const struct Expression *expr);
|
||||
bool rpn_isKnown(const struct Expression *expr);
|
||||
bool rpn_isSymbol(const struct Expression *expr);
|
||||
void rpn_Symbol(struct Expression *expr, char *tzSym);
|
||||
void rpn_Number(struct Expression *expr, uint32_t i);
|
||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
||||
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_OR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_AND(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
const struct Expression *src1,
|
||||
const struct Expression *src2);
|
||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
|
||||
void rpn_LOW(struct Expression *expr, const struct Expression *src);
|
||||
void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
|
||||
|
||||
200
src/asm/asmy.y
200
src/asm/asmy.y
@@ -18,7 +18,6 @@
|
||||
|
||||
#include "asm/asm.h"
|
||||
#include "asm/charmap.h"
|
||||
#include "asm/constexpr.h"
|
||||
#include "asm/fstack.h"
|
||||
#include "asm/lexer.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];
|
||||
struct Expression sVal;
|
||||
int32_t nConstValue;
|
||||
struct ConstExpression sConstExpr;
|
||||
}
|
||||
|
||||
%type <sVal> relocconst
|
||||
%type <sConstExpr> const
|
||||
%type <nConstValue> const
|
||||
%type <nConstValue> uconst
|
||||
%type <nConstValue> const_3bit
|
||||
%type <sVal> const_8bit
|
||||
@@ -966,17 +964,17 @@ global_list_entry : T_ID
|
||||
|
||||
equ : T_LABEL T_POP_EQU const
|
||||
{
|
||||
sym_AddEqu($1, constexpr_GetConstantValue(&$3));
|
||||
sym_AddEqu($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
set : T_LABEL T_POP_SET const
|
||||
{
|
||||
sym_AddSet($1, constexpr_GetConstantValue(&$3));
|
||||
sym_AddSet($1, $3);
|
||||
}
|
||||
| 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
|
||||
{
|
||||
int32_t value = constexpr_GetConstantValue(&$4);
|
||||
|
||||
if ((value & 0xFF) != value)
|
||||
if (($4 & 0xFF) != $4)
|
||||
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));
|
||||
}
|
||||
;
|
||||
@@ -1044,26 +1040,26 @@ printt : T_POP_PRINTT string
|
||||
|
||||
printv : T_POP_PRINTV const
|
||||
{
|
||||
printf("$%X", constexpr_GetConstantValue(&$2));
|
||||
printf("$%X", $2);
|
||||
}
|
||||
;
|
||||
|
||||
printi : T_POP_PRINTI const
|
||||
{
|
||||
printf("%d", constexpr_GetConstantValue(&$2));
|
||||
printf("%d", $2);
|
||||
}
|
||||
;
|
||||
|
||||
printf : T_POP_PRINTF const
|
||||
{
|
||||
math_Print(constexpr_GetConstantValue(&$2));
|
||||
math_Print($2);
|
||||
}
|
||||
;
|
||||
|
||||
if : T_POP_IF const
|
||||
{
|
||||
nIFDepth++;
|
||||
if (!constexpr_GetConstantValue(&$2)) {
|
||||
if (!$2) {
|
||||
/*
|
||||
* Continue parsing after ELSE, or at ELIF or
|
||||
* ENDC keyword.
|
||||
@@ -1095,7 +1091,7 @@ elif : T_POP_ELIF const
|
||||
*/
|
||||
skipElif = true;
|
||||
|
||||
if (!constexpr_GetConstantValue(&$2)) {
|
||||
if (!$2) {
|
||||
/*
|
||||
* Continue parsing after ELSE, or at
|
||||
* ELIF or ENDC keyword.
|
||||
@@ -1127,7 +1123,7 @@ endc : T_POP_ENDC
|
||||
|
||||
const_3bit : const
|
||||
{
|
||||
int32_t value = constexpr_GetConstantValue(&$1);
|
||||
int32_t value = $1;
|
||||
if ((value < 0) || (value > 7))
|
||||
yyerror("Immediate value must be 3-bit");
|
||||
else
|
||||
@@ -1190,7 +1186,7 @@ constlist_32bit_entry : /* empty */
|
||||
|
||||
const_8bit : relocconst
|
||||
{
|
||||
if( (!rpn_isReloc(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) )
|
||||
if( (rpn_isKnown(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) )
|
||||
warning(WARNING_TRUNCATION, "Expression must be 8-bit");
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -1198,7 +1194,7 @@ const_8bit : relocconst
|
||||
|
||||
const_16bit : relocconst
|
||||
{
|
||||
if ((!rpn_isReloc(&$1)) && (($1.nVal < -32768) || ($1.nVal > 65535)))
|
||||
if ((rpn_isKnown(&$1)) && (($1.nVal < -32768) || ($1.nVal > 65535)))
|
||||
warning(WARNING_TRUNCATION, "Expression must be 16-bit");
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -1223,24 +1219,24 @@ relocconst : T_ID
|
||||
rpn_Number(&$$, r);
|
||||
}
|
||||
| T_OP_LOGICNOT relocconst %prec NEG { rpn_LOGNOT(&$$, &$2); }
|
||||
| relocconst T_OP_LOGICOR relocconst { rpn_LOGOR(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICAND relocconst { rpn_LOGAND(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICEQU relocconst { rpn_LOGEQU(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICGT relocconst { rpn_LOGGT(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICLT relocconst { rpn_LOGLT(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICGE relocconst { rpn_LOGGE(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICLE relocconst { rpn_LOGLE(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICNE relocconst { rpn_LOGNE(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_ADD relocconst { rpn_ADD(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_SUB relocconst { rpn_SUB(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_XOR relocconst { rpn_XOR(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_OR relocconst { rpn_OR(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_AND relocconst { rpn_AND(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_SHL relocconst { rpn_SHL(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_SHR relocconst { rpn_SHR(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_MUL relocconst { rpn_MUL(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_DIV relocconst { rpn_DIV(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_MOD relocconst { rpn_MOD(&$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICOR relocconst { rpn_BinaryOp(RPN_LOGOR, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICAND relocconst { rpn_BinaryOp(RPN_LOGAND, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICEQU relocconst { rpn_BinaryOp(RPN_LOGEQ, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICGT relocconst { rpn_BinaryOp(RPN_LOGGT, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICLT relocconst { rpn_BinaryOp(RPN_LOGLT, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICGE relocconst { rpn_BinaryOp(RPN_LOGGE, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICLE relocconst { rpn_BinaryOp(RPN_LOGLE, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_LOGICNE relocconst { rpn_BinaryOp(RPN_LOGNE, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_ADD relocconst { rpn_BinaryOp(RPN_ADD, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_SUB relocconst { rpn_BinaryOp(RPN_SUB, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_XOR relocconst { rpn_BinaryOp(RPN_XOR, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_OR relocconst { rpn_BinaryOp(RPN_OR, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_AND relocconst { rpn_BinaryOp(RPN_AND, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_SHL relocconst { rpn_BinaryOp(RPN_SHL, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_SHR relocconst { rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_MUL relocconst { rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_DIV relocconst { rpn_BinaryOp(RPN_DIV, &$$, &$1, &$3); }
|
||||
| relocconst T_OP_MOD relocconst { rpn_BinaryOp(RPN_MOD, &$$, &$1, &$3); }
|
||||
| T_OP_ADD relocconst %prec NEG { $$ = $2; }
|
||||
| T_OP_SUB relocconst %prec NEG { rpn_UNNEG(&$$, &$2); }
|
||||
| T_OP_NOT relocconst %prec NEG { rpn_UNNOT(&$$, &$2); }
|
||||
@@ -1268,57 +1264,57 @@ relocconst : T_ID
|
||||
}
|
||||
| T_OP_ROUND '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_Round($3));
|
||||
}
|
||||
| T_OP_CEIL '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_Ceil($3));
|
||||
}
|
||||
| T_OP_FLOOR '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_Floor($3));
|
||||
}
|
||||
| T_OP_FDIV '(' const comma const ')'
|
||||
{
|
||||
rpn_Number(&$$,
|
||||
math_Div(constexpr_GetConstantValue(&$3),
|
||||
constexpr_GetConstantValue(&$5)));
|
||||
math_Div($3,
|
||||
$5));
|
||||
}
|
||||
| T_OP_FMUL '(' const comma const ')'
|
||||
{
|
||||
rpn_Number(&$$,
|
||||
math_Mul(constexpr_GetConstantValue(&$3),
|
||||
constexpr_GetConstantValue(&$5)));
|
||||
math_Mul($3,
|
||||
$5));
|
||||
}
|
||||
| T_OP_SIN '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_Sin(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_Sin($3));
|
||||
}
|
||||
| T_OP_COS '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_Cos(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_Cos($3));
|
||||
}
|
||||
| T_OP_TAN '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_Tan(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_Tan($3));
|
||||
}
|
||||
| T_OP_ASIN '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_ASin(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_ASin($3));
|
||||
}
|
||||
| T_OP_ACOS '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_ACos(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_ACos($3));
|
||||
}
|
||||
| T_OP_ATAN '(' const ')'
|
||||
{
|
||||
rpn_Number(&$$, math_ATan(constexpr_GetConstantValue(&$3)));
|
||||
rpn_Number(&$$, math_ATan($3));
|
||||
}
|
||||
| T_OP_ATAN2 '(' const comma const ')'
|
||||
{
|
||||
rpn_Number(&$$,
|
||||
math_ATan2(constexpr_GetConstantValue(&$3),
|
||||
constexpr_GetConstantValue(&$5)));
|
||||
math_ATan2($3,
|
||||
$5));
|
||||
}
|
||||
| T_OP_STRCMP '(' string comma string ')'
|
||||
{
|
||||
@@ -1339,92 +1335,23 @@ relocconst : T_ID
|
||||
|
||||
uconst : const
|
||||
{
|
||||
int32_t value = constexpr_GetConstantValue(&$1);
|
||||
int32_t value = $1;
|
||||
if (value < 0)
|
||||
fatalerror("Constant mustn't be negative: %d", value);
|
||||
$$ = value;
|
||||
}
|
||||
;
|
||||
|
||||
const : T_ID { constexpr_Symbol(&$$, $1); }
|
||||
| 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 ')'
|
||||
const : relocconst
|
||||
{
|
||||
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
|
||||
@@ -1769,7 +1696,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind
|
||||
{
|
||||
rpn_CheckHRAM(&$4, &$4);
|
||||
|
||||
if ((!rpn_isReloc(&$4)) && ($4.nVal < 0 || ($4.nVal > 0xFF && $4.nVal < 0xFF00) || $4.nVal > 0xFFFF))
|
||||
if ((rpn_isKnown(&$4)) && ($4.nVal < 0 || ($4.nVal > 0xFF && $4.nVal < 0xFF00) || $4.nVal > 0xFFFF))
|
||||
yyerror("Source address $%x not in $FF00 to $FFFF", $4.nVal);
|
||||
|
||||
out_AbsByte(0xF0);
|
||||
@@ -1780,7 +1707,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind
|
||||
{
|
||||
rpn_CheckHRAM(&$2, &$2);
|
||||
|
||||
if ((!rpn_isReloc(&$2)) && ($2.nVal < 0 || ($2.nVal > 0xFF && $2.nVal < 0xFF00) || $2.nVal > 0xFFFF))
|
||||
if ((rpn_isKnown(&$2)) && ($2.nVal < 0 || ($2.nVal > 0xFF && $2.nVal < 0xFF00) || $2.nVal > 0xFFFF))
|
||||
yyerror("Destination address $%x not in $FF00 to $FFFF", $2.nVal);
|
||||
|
||||
out_AbsByte(0xE0);
|
||||
@@ -1844,7 +1771,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind comma T_MODE_SP
|
||||
| T_Z80_LD op_mem_ind comma T_MODE_A
|
||||
{
|
||||
if (CurrentOptions.optimizeloads &&
|
||||
(!rpn_isReloc(&$2)) && ($2.nVal >= 0xFF00)) {
|
||||
(rpn_isKnown(&$2)) && ($2.nVal >= 0xFF00)) {
|
||||
out_AbsByte(0xE0);
|
||||
out_AbsByte($2.nVal & 0xFF);
|
||||
rpn_Free(&$2);
|
||||
@@ -1899,7 +1826,7 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND
|
||||
{
|
||||
if ($2 == REG_A) {
|
||||
if (CurrentOptions.optimizeloads &&
|
||||
(!rpn_isReloc(&$4)) && ($4.nVal >= 0xFF00)) {
|
||||
(rpn_isKnown(&$4)) && ($4.nVal >= 0xFF00)) {
|
||||
out_AbsByte(0xF0);
|
||||
out_AbsByte($4.nVal & 0xFF);
|
||||
rpn_Free(&$4);
|
||||
@@ -2036,13 +1963,14 @@ z80_rrca : T_Z80_RRCA
|
||||
|
||||
z80_rst : T_Z80_RST const_8bit
|
||||
{
|
||||
if (rpn_isReloc(&$2)) {
|
||||
if (!rpn_isKnown(&$2)) {
|
||||
rpn_CheckRST(&$2, &$2);
|
||||
out_RelByte(&$2);
|
||||
} else if (($2.nVal & 0x38) != $2.nVal)
|
||||
} else if (($2.nVal & 0x38) != $2.nVal) {
|
||||
yyerror("Invalid address $%x for RST", $2.nVal);
|
||||
else
|
||||
} else {
|
||||
out_AbsByte(0xC7 | $2.nVal);
|
||||
}
|
||||
rpn_Free(&$2);
|
||||
}
|
||||
;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asm/asm.h"
|
||||
#include "asm/constexpr.h"
|
||||
#include "asm/lexer.h"
|
||||
#include "asm/main.h"
|
||||
#include "asm/rpn.h"
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asm/asm.h"
|
||||
#include "asm/constexpr.h"
|
||||
#include "asm/fstack.h"
|
||||
#include "asm/lexer.h"
|
||||
#include "asm/main.h"
|
||||
|
||||
@@ -800,7 +800,7 @@ void out_RelByte(struct Expression *expr)
|
||||
{
|
||||
checkcodesection();
|
||||
checksectionoverflow(1);
|
||||
if (rpn_isReloc(expr)) {
|
||||
if (!rpn_isKnown(expr)) {
|
||||
pCurrentSection->tData[nPC] = 0;
|
||||
createpatch(PATCHTYPE_BYTE, expr);
|
||||
pCurrentSection->nPC++;
|
||||
@@ -835,7 +835,7 @@ void out_RelWord(struct Expression *expr)
|
||||
{
|
||||
checkcodesection();
|
||||
checksectionoverflow(2);
|
||||
if (rpn_isReloc(expr)) {
|
||||
if (!rpn_isKnown(expr)) {
|
||||
pCurrentSection->tData[nPC] = 0;
|
||||
pCurrentSection->tData[nPC + 1] = 0;
|
||||
createpatch(PATCHTYPE_WORD, expr);
|
||||
@@ -872,7 +872,7 @@ void out_RelLong(struct Expression *expr)
|
||||
{
|
||||
checkcodesection();
|
||||
checksectionoverflow(4);
|
||||
if (rpn_isReloc(expr)) {
|
||||
if (!rpn_isKnown(expr)) {
|
||||
pCurrentSection->tData[nPC] = 0;
|
||||
pCurrentSection->tData[nPC + 1] = 0;
|
||||
pCurrentSection->tData[nPC + 2] = 0;
|
||||
@@ -895,14 +895,25 @@ void out_PCRelByte(struct Expression *expr)
|
||||
{
|
||||
checkcodesection();
|
||||
checksectionoverflow(1);
|
||||
if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
|
||||
pCurrentSection->tData[nPC] = 0;
|
||||
createpatch(PATCHTYPE_JR, expr);
|
||||
pCurrentSection->nPC++;
|
||||
nPC++;
|
||||
pPCSymbol->nValue++;
|
||||
} else {
|
||||
/* Target is relative to the byte *after* the operand */
|
||||
uint16_t address = pCurrentSection->nOrg + nPC + 1;
|
||||
/* The offset wraps (jump from ROM to HRAM, for loopexample) */
|
||||
int16_t offset = expr->nVal - address;
|
||||
|
||||
/* Always let the linker calculate the offset. */
|
||||
pCurrentSection->tData[nPC] = 0;
|
||||
createpatch(PATCHTYPE_JR, expr);
|
||||
pCurrentSection->nPC++;
|
||||
nPC++;
|
||||
pPCSymbol->nValue++;
|
||||
|
||||
if (offset < -128 || offset > 127) {
|
||||
yyerror("jr target out of reach (expected -129 < %d < 128)", offset);
|
||||
out_AbsByte(0);
|
||||
} else {
|
||||
out_AbsByte(offset);
|
||||
}
|
||||
}
|
||||
rpn_Free(expr);
|
||||
}
|
||||
|
||||
|
||||
666
src/asm/rpn.c
666
src/asm/rpn.c
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -22,67 +23,50 @@
|
||||
#include "asm/output.h"
|
||||
#include "asm/warning.h"
|
||||
|
||||
#include "linkdefs.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)
|
||||
|
||||
void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
||||
{
|
||||
assert(src1->tRPN != NULL && src2->tRPN != NULL);
|
||||
|
||||
if (src1->nRPNLength + src2->nRPNLength > MAXRPNLEN)
|
||||
fatalerror("RPN expression is too large");
|
||||
|
||||
uint32_t len = src1->nRPNLength + src2->nRPNLength;
|
||||
|
||||
expr->nVal = 0;
|
||||
expr->tRPN = src1->tRPN;
|
||||
|
||||
if (src1->nRPNCapacity >= len) {
|
||||
expr->nRPNCapacity = src1->nRPNCapacity;
|
||||
} else {
|
||||
uint32_t cap1 = src1->nRPNCapacity;
|
||||
uint32_t cap2 = src2->nRPNCapacity;
|
||||
uint32_t cap = (cap1 > cap2) ? cap1 : cap2;
|
||||
|
||||
if (len > cap)
|
||||
cap = (cap <= MAXRPNLEN / 2) ? cap * 2 : MAXRPNLEN;
|
||||
|
||||
expr->nRPNCapacity = cap;
|
||||
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
|
||||
if (expr->tRPN == NULL)
|
||||
fatalerror("No memory for RPN expression");
|
||||
}
|
||||
|
||||
memcpy(expr->tRPN + src1->nRPNLength, src2->tRPN, src2->nRPNLength);
|
||||
free(src2->tRPN);
|
||||
|
||||
expr->nRPNLength = len;
|
||||
expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize;
|
||||
expr->nRPNOut = 0;
|
||||
expr->isReloc = src1->isReloc || src2->isReloc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a byte to the RPN expression
|
||||
*/
|
||||
void pushbyte(struct Expression *expr, uint8_t b)
|
||||
{
|
||||
if (expr->nRPNLength == expr->nRPNCapacity) {
|
||||
if (expr->nRPNCapacity == 0)
|
||||
expr->nRPNCapacity = 256;
|
||||
else if (expr->nRPNCapacity == MAXRPNLEN)
|
||||
fatalerror("RPN expression is too large");
|
||||
/* This assumes the RPN length is always less than the capacity */
|
||||
if (expr->nRPNCapacity - expr->nRPNLength < 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)
|
||||
/*
|
||||
* To avoid generating humongous object files, cap the
|
||||
* size of RPN expressions
|
||||
*/
|
||||
fatalerror("RPN expression cannot grow larger than %d bytes",
|
||||
MAXRPNLEN);
|
||||
else if (expr->nRPNCapacity > MAXRPNLEN / 2)
|
||||
expr->nRPNCapacity = MAXRPNLEN;
|
||||
else
|
||||
expr->nRPNCapacity *= 2;
|
||||
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
|
||||
|
||||
if (expr->tRPN == NULL)
|
||||
fatalerror("No memory for RPN expression");
|
||||
if (!expr->tRPN)
|
||||
fatalerror("Failed to grow RPN expression: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
expr->tRPN[expr->nRPNLength++] = b;
|
||||
uint8_t *ptr = expr->tRPN + expr->nRPNLength;
|
||||
|
||||
expr->nRPNLength += size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -90,12 +74,14 @@ void pushbyte(struct Expression *expr, uint8_t b)
|
||||
*/
|
||||
void rpn_Init(struct Expression *expr)
|
||||
{
|
||||
expr->reason = NULL;
|
||||
expr->isKnown = true;
|
||||
expr->isSymbol = false;
|
||||
expr->tRPN = NULL;
|
||||
expr->nRPNCapacity = 0;
|
||||
expr->nRPNLength = 0;
|
||||
expr->nRPNPatchSize = 0;
|
||||
expr->nRPNOut = 0;
|
||||
expr->isReloc = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -104,6 +90,7 @@ void rpn_Init(struct Expression *expr)
|
||||
void rpn_Free(struct Expression *expr)
|
||||
{
|
||||
free(expr->tRPN);
|
||||
free(expr->reason);
|
||||
rpn_Init(expr);
|
||||
}
|
||||
|
||||
@@ -119,11 +106,19 @@ uint16_t rpn_PopByte(struct Expression *expr)
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the current expression is relocatable
|
||||
* Determine if the current expression is known at assembly time
|
||||
*/
|
||||
uint32_t rpn_isReloc(const struct Expression *expr)
|
||||
bool rpn_isKnown(const struct Expression *expr)
|
||||
{
|
||||
return expr->isReloc;
|
||||
return expr->isKnown;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if the current expression is a symbol suitable for const diffing
|
||||
*/
|
||||
bool rpn_isSymbol(const struct Expression *expr)
|
||||
{
|
||||
return expr->isSymbol;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -132,13 +127,7 @@ uint32_t rpn_isReloc(const struct Expression *expr)
|
||||
void rpn_Number(struct Expression *expr, uint32_t i)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
pushbyte(expr, RPN_CONST);
|
||||
pushbyte(expr, i);
|
||||
pushbyte(expr, i >> 8);
|
||||
pushbyte(expr, i >> 16);
|
||||
pushbyte(expr, i >> 24);
|
||||
expr->nVal = i;
|
||||
expr->nRPNPatchSize += 5;
|
||||
}
|
||||
|
||||
void rpn_Symbol(struct Expression *expr, char *tzSym)
|
||||
@@ -147,20 +136,28 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
|
||||
|
||||
if (!sym || !sym_IsConstant(sym)) {
|
||||
rpn_Init(expr);
|
||||
expr->isSymbol = true;
|
||||
|
||||
sym_Ref(tzSym);
|
||||
expr->isReloc = 1;
|
||||
pushbyte(expr, RPN_SYM);
|
||||
while (*tzSym)
|
||||
pushbyte(expr, *tzSym++);
|
||||
pushbyte(expr, 0);
|
||||
expr->nRPNPatchSize += 5;
|
||||
makeUnknown(expr, strcmp(tzSym, "@")
|
||||
? "'%s' is not constant at assembly time"
|
||||
: "PC is not constant at assembly time",
|
||||
tzSym);
|
||||
expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */
|
||||
|
||||
size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
*ptr++ = RPN_SYM;
|
||||
memcpy(ptr, tzSym, nameLen);
|
||||
|
||||
/* RGBLINK assumes PC is at the byte being computed... */
|
||||
if (sym == pPCSymbol && nPCOffset) {
|
||||
struct Expression pc = *expr, offset;
|
||||
|
||||
rpn_Number(&offset, nPCOffset);
|
||||
rpn_SUB(expr, &pc, &offset);
|
||||
rpn_BinaryOp(RPN_SUB, expr, &pc, &offset);
|
||||
if (!rpn_isKnown(expr))
|
||||
expr->isSymbol = true;
|
||||
}
|
||||
} else {
|
||||
rpn_Number(expr, sym_GetConstantValue(tzSym));
|
||||
@@ -171,17 +168,13 @@ void rpn_BankSelf(struct Expression *expr)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
|
||||
if (pCurrentSection->nBank == -1)
|
||||
/*
|
||||
* This is not really relocatable, but this makes the assembler
|
||||
* write this expression as a RPN patch to the object file.
|
||||
*/
|
||||
expr->isReloc = 1;
|
||||
else
|
||||
if (pCurrentSection->nBank == -1) {
|
||||
makeUnknown(expr, "Current section's bank is not known");
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_BANK_SELF;
|
||||
} else {
|
||||
expr->nVal = pCurrentSection->nBank;
|
||||
|
||||
pushbyte(expr, RPN_BANK_SELF);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
||||
@@ -194,25 +187,26 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
||||
return;
|
||||
}
|
||||
|
||||
rpn_Init(expr);
|
||||
if (sym && sym_IsConstant(sym)) {
|
||||
yyerror("BANK argument must be a relocatable identifier");
|
||||
} else {
|
||||
rpn_Init(expr);
|
||||
sym_Ref(tzSym);
|
||||
pushbyte(expr, RPN_BANK_SYM);
|
||||
for (unsigned int i = 0; tzSym[i]; i++)
|
||||
pushbyte(expr, tzSym[i]);
|
||||
pushbyte(expr, 0);
|
||||
expr->nRPNPatchSize += 5;
|
||||
|
||||
/* If the symbol didn't exist, `sym_Ref` created it */
|
||||
struct sSymbol *pSymbol = sym_FindSymbol(tzSym);
|
||||
|
||||
if (pSymbol->pSection && pSymbol->pSection->nBank != -1)
|
||||
/* Symbol's section is known and bank's fixed */
|
||||
if (pSymbol->pSection && pSymbol->pSection->nBank != -1) {
|
||||
/* Symbol's section is known and bank is fixed */
|
||||
expr->nVal = pSymbol->pSection->nBank;
|
||||
else
|
||||
expr->isReloc = 1;
|
||||
} else {
|
||||
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! */
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
*ptr++ = RPN_BANK_SYM;
|
||||
memcpy(ptr, tzSym, nameLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,213 +216,61 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName)
|
||||
|
||||
struct Section *pSection = out_FindSectionByName(tzSectionName);
|
||||
|
||||
if (pSection && pSection->nBank != -1)
|
||||
if (pSection && pSection->nBank != -1) {
|
||||
expr->nVal = pSection->nBank;
|
||||
else
|
||||
/*
|
||||
* This is not really relocatable, but this makes the assembler
|
||||
* write this expression as a RPN patch to the object file.
|
||||
*/
|
||||
expr->isReloc = 1;
|
||||
} else {
|
||||
makeUnknown(expr, "Section \"%s\"'s bank is not known",
|
||||
tzSectionName);
|
||||
|
||||
pushbyte(expr, RPN_BANK_SECT);
|
||||
expr->nRPNPatchSize++;
|
||||
size_t nameLen = strlen(tzSectionName) + 1; /* Room for NUL! */
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
|
||||
while (*tzSectionName) {
|
||||
pushbyte(expr, *tzSectionName++);
|
||||
expr->nRPNPatchSize++;
|
||||
expr->nRPNPatchSize += nameLen + 1;
|
||||
*ptr++ = RPN_BANK_SECT;
|
||||
memcpy(ptr, tzSectionName, nameLen);
|
||||
}
|
||||
|
||||
pushbyte(expr, 0);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
pushbyte(expr, RPN_HRAM);
|
||||
expr->nRPNPatchSize++;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
/* TODO */
|
||||
} else {
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_HRAM;
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
pushbyte(expr, RPN_RST);
|
||||
expr->nRPNPatchSize++;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
/* TODO */
|
||||
} else {
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_RST;
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
expr->nVal = !expr->nVal;
|
||||
pushbyte(expr, RPN_LOGUNNOT);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
expr->isSymbol = false;
|
||||
|
||||
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal || src2->nVal);
|
||||
pushbyte(expr, RPN_LOGOR);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal && src2->nVal);
|
||||
pushbyte(expr, RPN_LOGAND);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
|
||||
expr->nVal = (expr->nVal >> 8) & 0xFF;
|
||||
|
||||
pushbyte(expr, RPN_CONST);
|
||||
pushbyte(expr, 8);
|
||||
pushbyte(expr, 0);
|
||||
pushbyte(expr, 0);
|
||||
pushbyte(expr, 0);
|
||||
|
||||
pushbyte(expr, RPN_SHR);
|
||||
|
||||
pushbyte(expr, RPN_CONST);
|
||||
pushbyte(expr, 0xFF);
|
||||
pushbyte(expr, 0);
|
||||
pushbyte(expr, 0);
|
||||
pushbyte(expr, 0);
|
||||
|
||||
pushbyte(expr, RPN_AND);
|
||||
|
||||
expr->nRPNPatchSize += 12;
|
||||
}
|
||||
|
||||
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
|
||||
expr->nVal = expr->nVal & 0xFF;
|
||||
|
||||
pushbyte(expr, RPN_CONST);
|
||||
pushbyte(expr, 0xFF);
|
||||
pushbyte(expr, 0);
|
||||
pushbyte(expr, 0);
|
||||
pushbyte(expr, 0);
|
||||
|
||||
pushbyte(expr, RPN_AND);
|
||||
|
||||
expr->nRPNPatchSize += 6;
|
||||
}
|
||||
|
||||
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal == src2->nVal);
|
||||
pushbyte(expr, RPN_LOGEQ);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal > src2->nVal);
|
||||
pushbyte(expr, RPN_LOGGT);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal < src2->nVal);
|
||||
pushbyte(expr, RPN_LOGLT);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal >= src2->nVal);
|
||||
pushbyte(expr, RPN_LOGGE);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal <= src2->nVal);
|
||||
pushbyte(expr, RPN_LOGLE);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal != src2->nVal);
|
||||
pushbyte(expr, RPN_LOGNE);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = ((uint32_t)src1->nVal + (uint32_t)src2->nVal);
|
||||
pushbyte(expr, RPN_ADD);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = ((uint32_t)src1->nVal - (uint32_t)src2->nVal);
|
||||
pushbyte(expr, RPN_SUB);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal ^ src2->nVal);
|
||||
pushbyte(expr, RPN_XOR);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_OR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal | src2->nVal);
|
||||
pushbyte(expr, RPN_OR);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
|
||||
void rpn_AND(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = (src1->nVal & src2->nVal);
|
||||
pushbyte(expr, RPN_AND);
|
||||
expr->nRPNPatchSize++;
|
||||
if (rpn_isKnown(expr)) {
|
||||
expr->nVal = !expr->nVal;
|
||||
} else {
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_LOGUNNOT;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t shift(int32_t shiftee, int32_t amount)
|
||||
{
|
||||
if (shiftee < 0)
|
||||
warning(WARNING_SHIFT, "Shifting negative value %d", shiftee);
|
||||
|
||||
if (amount >= 0) {
|
||||
// Left shift
|
||||
if (amount >= 32) {
|
||||
@@ -466,101 +308,247 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
static struct sSymbol const *symbolOf(struct Expression const *expr)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
|
||||
if (!expr->isReloc) {
|
||||
if (src2->nVal < 0)
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d",
|
||||
src2->nVal);
|
||||
|
||||
expr->nVal = shift(src1->nVal, src2->nVal);
|
||||
}
|
||||
|
||||
pushbyte(expr, RPN_SHL);
|
||||
expr->nRPNPatchSize++;
|
||||
if (!rpn_isSymbol(expr))
|
||||
return NULL;
|
||||
return sym_FindSymbol((char *)expr->tRPN + 1);
|
||||
}
|
||||
|
||||
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
static bool isDiffConstant(struct Expression const *src1,
|
||||
struct Expression const *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
/* Check if both expressions only refer to a single symbol */
|
||||
struct sSymbol const *symbol1 = symbolOf(src1);
|
||||
struct sSymbol const *symbol2 = symbolOf(src2);
|
||||
|
||||
if (!expr->isReloc) {
|
||||
if (src2->nVal < 0)
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d",
|
||||
src2->nVal);
|
||||
if (!symbol1 || !symbol2
|
||||
|| symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL)
|
||||
return false;
|
||||
|
||||
expr->nVal = shift(src1->nVal, -src2->nVal);
|
||||
}
|
||||
|
||||
pushbyte(expr, RPN_SHR);
|
||||
expr->nRPNPatchSize++;
|
||||
return symbol1->pSection == symbol2->pSection;
|
||||
}
|
||||
|
||||
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
const struct Expression *src1, const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
expr->nVal = ((uint32_t)src1->nVal * (uint32_t)src2->nVal);
|
||||
pushbyte(expr, RPN_MUL);
|
||||
expr->nRPNPatchSize++;
|
||||
}
|
||||
expr->isSymbol = false;
|
||||
|
||||
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
/* First, check if the expression is known */
|
||||
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||
if (expr->isKnown) {
|
||||
rpn_Init(expr); /* Init the expression to something sane */
|
||||
|
||||
if (!expr->isReloc) {
|
||||
if (src2->nVal == 0)
|
||||
fatalerror("Division by zero");
|
||||
/* If both expressions are known, just compute the value */
|
||||
uint32_t uleft = src1->nVal, uright = src2->nVal;
|
||||
|
||||
if (src1->nVal == INT32_MIN && src2->nVal == -1) {
|
||||
warning(WARNING_DIV, "Division of min value by -1");
|
||||
expr->nVal = INT32_MIN;
|
||||
} else {
|
||||
expr->nVal = (src1->nVal / src2->nVal);
|
||||
switch (op) {
|
||||
case RPN_LOGOR:
|
||||
expr->nVal = src1->nVal || src2->nVal;
|
||||
break;
|
||||
case RPN_LOGAND:
|
||||
expr->nVal = src1->nVal && src2->nVal;
|
||||
break;
|
||||
case RPN_LOGEQ:
|
||||
expr->nVal = src1->nVal == src2->nVal;
|
||||
break;
|
||||
case RPN_LOGGT:
|
||||
expr->nVal = src1->nVal > src2->nVal;
|
||||
break;
|
||||
case RPN_LOGLT:
|
||||
expr->nVal = src1->nVal < src2->nVal;
|
||||
break;
|
||||
case RPN_LOGGE:
|
||||
expr->nVal = src1->nVal >= src2->nVal;
|
||||
break;
|
||||
case RPN_LOGLE:
|
||||
expr->nVal = src1->nVal <= src2->nVal;
|
||||
break;
|
||||
case RPN_LOGNE:
|
||||
expr->nVal = src1->nVal != src2->nVal;
|
||||
break;
|
||||
case RPN_ADD:
|
||||
expr->nVal = uleft + uright;
|
||||
break;
|
||||
case RPN_SUB:
|
||||
expr->nVal = uleft - uright;
|
||||
break;
|
||||
case RPN_XOR:
|
||||
expr->nVal = src1->nVal ^ src2->nVal;
|
||||
break;
|
||||
case RPN_OR:
|
||||
expr->nVal = src1->nVal | src2->nVal;
|
||||
break;
|
||||
case RPN_AND:
|
||||
expr->nVal = src1->nVal & src2->nVal;
|
||||
break;
|
||||
case RPN_SHL:
|
||||
if (src2->nVal < 0)
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %d",
|
||||
src2->nVal);
|
||||
|
||||
expr->nVal = shift(src1->nVal, src2->nVal);
|
||||
break;
|
||||
case RPN_SHR:
|
||||
if (src1->nVal < 0)
|
||||
warning(WARNING_SHIFT, "Shifting negative value %d",
|
||||
src1->nVal);
|
||||
|
||||
if (src2->nVal < 0)
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %d",
|
||||
src2->nVal);
|
||||
|
||||
expr->nVal = shift(src1->nVal, -src2->nVal);
|
||||
break;
|
||||
case RPN_MUL:
|
||||
expr->nVal = uleft * uright;
|
||||
break;
|
||||
case RPN_DIV:
|
||||
if (src2->nVal == 0)
|
||||
fatalerror("Division by zero");
|
||||
|
||||
if (src1->nVal == INT32_MIN
|
||||
&& src2->nVal == -1) {
|
||||
warning(WARNING_DIV, "Division of min value by -1");
|
||||
expr->nVal = INT32_MIN;
|
||||
} else {
|
||||
expr->nVal = src1->nVal / src2->nVal;
|
||||
}
|
||||
break;
|
||||
case RPN_MOD:
|
||||
if (src2->nVal == 0)
|
||||
fatalerror("Division by zero");
|
||||
|
||||
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||
expr->nVal = 0;
|
||||
else
|
||||
expr->nVal = src1->nVal % src2->nVal;
|
||||
break;
|
||||
|
||||
case RPN_UNSUB:
|
||||
case RPN_UNNOT:
|
||||
case RPN_LOGUNNOT:
|
||||
case RPN_BANK_SYM:
|
||||
case RPN_BANK_SECT:
|
||||
case RPN_BANK_SELF:
|
||||
case RPN_HRAM:
|
||||
case RPN_RST:
|
||||
case RPN_CONST:
|
||||
case RPN_SYM:
|
||||
fatalerror("%d is no binary operator", op);
|
||||
}
|
||||
}
|
||||
|
||||
pushbyte(expr, RPN_DIV);
|
||||
expr->nRPNPatchSize++;
|
||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||
struct sSymbol const *symbol1 = symbolOf(src1);
|
||||
struct sSymbol const *symbol2 = symbolOf(src2);
|
||||
|
||||
expr->nVal = symbol1->nValue - symbol2->nValue;
|
||||
expr->isKnown = true;
|
||||
} else {
|
||||
/* If it's not known, start computing the RPN expression */
|
||||
|
||||
/* Convert the left-hand expression if it's constant */
|
||||
if (src1->isKnown) {
|
||||
uint32_t lval = src1->nVal;
|
||||
uint8_t bytes[] = {RPN_CONST, lval, lval >> 8,
|
||||
lval >> 16, lval >> 24};
|
||||
expr->nRPNPatchSize = sizeof(bytes);
|
||||
expr->tRPN = NULL;
|
||||
expr->nRPNCapacity = 0;
|
||||
expr->nRPNLength = 0;
|
||||
memcpy(reserveSpace(expr, sizeof(bytes)), bytes,
|
||||
sizeof(bytes));
|
||||
|
||||
/* Use the other expression's un-const reason */
|
||||
expr->reason = src2->reason;
|
||||
free(src1->reason);
|
||||
} else {
|
||||
/* Otherwise just reuse its RPN buffer */
|
||||
expr->nRPNPatchSize = src1->nRPNPatchSize;
|
||||
expr->tRPN = src1->tRPN;
|
||||
expr->nRPNCapacity = src1->nRPNCapacity;
|
||||
expr->nRPNLength = src1->nRPNLength;
|
||||
expr->reason = src1->reason;
|
||||
free(src2->reason);
|
||||
}
|
||||
|
||||
/* Now, merge the right expression into the left one */
|
||||
uint8_t *ptr = src2->tRPN; /* Pointer to the right RPN */
|
||||
uint32_t len = src2->nRPNLength; /* Size of the right RPN */
|
||||
uint32_t patchSize = src2->nRPNPatchSize;
|
||||
|
||||
/* If the right expression is constant, merge a shim instead */
|
||||
uint32_t rval = src2->nVal;
|
||||
uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16,
|
||||
rval >> 24};
|
||||
if (src2->isKnown) {
|
||||
ptr = bytes;
|
||||
len = sizeof(bytes);
|
||||
patchSize = sizeof(bytes);
|
||||
}
|
||||
/* Copy the right RPN and append the operator */
|
||||
uint8_t *buf = reserveSpace(expr, len + 1);
|
||||
|
||||
memcpy(buf, ptr, len);
|
||||
buf[len] = op;
|
||||
|
||||
free(src2->tRPN); /* If there was none, this is `free(NULL)` */
|
||||
expr->nRPNPatchSize += patchSize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
|
||||
const struct Expression *src2)
|
||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
mergetwoexpressions(expr, src1, src2);
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (!expr->isReloc) {
|
||||
if (src2->nVal == 0)
|
||||
fatalerror("Division by zero");
|
||||
|
||||
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||
expr->nVal = 0;
|
||||
else
|
||||
expr->nVal = (src1->nVal % src2->nVal);
|
||||
if (rpn_isKnown(expr)) {
|
||||
expr->nVal = (uint32_t)expr->nVal >> 8 & 0xFF;
|
||||
} else {
|
||||
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
||||
RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||
expr->nRPNPatchSize += sizeof(bytes);
|
||||
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
pushbyte(expr, RPN_MOD);
|
||||
expr->nRPNPatchSize++;
|
||||
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
expr->nVal = expr->nVal & 0xFF;
|
||||
} else {
|
||||
uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||
|
||||
expr->nRPNPatchSize += sizeof(bytes);
|
||||
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
expr->nVal = -(uint32_t)expr->nVal;
|
||||
pushbyte(expr, RPN_UNSUB);
|
||||
expr->nRPNPatchSize++;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
expr->nVal = -(uint32_t)expr->nVal;
|
||||
} else {
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_UNSUB;
|
||||
}
|
||||
}
|
||||
|
||||
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
expr->nVal = ~expr->nVal;
|
||||
pushbyte(expr, RPN_UNNOT);
|
||||
expr->nRPNPatchSize++;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
expr->nVal = ~expr->nVal;
|
||||
} else {
|
||||
expr->nRPNPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_UNNOT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ uint32_t sym_GetConstantValue(char const *s)
|
||||
if (sym_IsConstant(psym))
|
||||
return getvaluefield(psym);
|
||||
|
||||
fatalerror("Expression must have a constant value");
|
||||
fatalerror("\"%s\" does not have a constant value", s);
|
||||
}
|
||||
|
||||
yyerror("'%s' not defined", s);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
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)!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ERROR: bracketed-symbols.asm(16):
|
||||
Print types are only allowed for numbers
|
||||
ERROR: bracketed-symbols.asm(20):
|
||||
Expression must have a constant value
|
||||
"Label" does not have a constant value
|
||||
|
||||
@@ -31,20 +31,22 @@ POPS ; Ensure we are in neither section
|
||||
; Diffing two labels in the same SECTION as well
|
||||
print_diff Known2, Known
|
||||
; Diffing a constant and a "floating" label cannot work
|
||||
; ...And that causes a fatal error print_diff Constant, Known
|
||||
print_diff Constant, Known
|
||||
; Diffing a constant and a ref cannot work
|
||||
; ...And that causes a fatal error print_diff Constant, Unknown
|
||||
print_diff Constant, Unknown
|
||||
; Diffing a floating label and a ref cannot work
|
||||
; ...And that causes a fatal error print_diff Known, Unknown
|
||||
print_diff Known, Unknown
|
||||
; Diffing two refs cannot work
|
||||
print_diff Unknown, Unknown2
|
||||
|
||||
; Now let's fiddle with PC
|
||||
SECTION "fixed PC", ROM0[420]
|
||||
; Diffing a constant and PC should work
|
||||
print_diff Constant, @
|
||||
; Diffing a floating label and PC cannot work
|
||||
; ...And that causes a fatal error print_diff Known, @
|
||||
print_diff Known, @
|
||||
; Diffinf a ref and PC cannot work
|
||||
; ...And that causes a fatal error print_diff Unknown, @
|
||||
print_diff Unknown, @
|
||||
; Diffing PC and PC should work
|
||||
print_diff @, @
|
||||
; Diffing PC and a label from here should work
|
||||
@@ -53,11 +55,11 @@ LocalFixed:
|
||||
|
||||
SECTION "Floating PC", ROM0
|
||||
; Diffing a constant and PC cannot work
|
||||
; ...And that causes a fatal error print_diff Constant, @
|
||||
print_diff Constant, @
|
||||
; Diffing a floating label and PC cannot work
|
||||
; ...And that causes a fatal error print_diff Known, @
|
||||
print_diff Known, @
|
||||
; Diffinf a ref and PC cannot work
|
||||
; ...And that causes a fatal error print_diff Unknown, @
|
||||
print_diff Unknown, @
|
||||
; Diffing PC and PC should work
|
||||
print_diff @, @
|
||||
; Diffing PC and a label from here should work
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
ERROR: label-diff.asm(34) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Known' is not constant at assembly time
|
||||
ERROR: label-diff.asm(34) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: 'Known' is not constant at assembly time
|
||||
ERROR: label-diff.asm(36) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(36) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Known' is not constant at assembly time
|
||||
ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(40) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(40) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: 'Unknown2' is not constant at assembly time
|
||||
ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Known' is not constant at assembly time
|
||||
ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: 'Known' is not constant at assembly time
|
||||
ERROR: label-diff.asm(49) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(49) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: PC is not constant at assembly time
|
||||
ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: PC is not constant at assembly time
|
||||
ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Known' is not constant at assembly time
|
||||
ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: PC is not constant at assembly time
|
||||
ERROR: label-diff.asm(62) -> label-diff.asm::print_diff(20):
|
||||
Expected constant expression: 'Unknown' is not constant at assembly time
|
||||
ERROR: label-diff.asm(62) -> label-diff.asm::print_diff(22):
|
||||
Expected constant expression: PC is not constant at assembly time
|
||||
error: Assembly aborted (18 errors)!
|
||||
|
||||
@@ -2,6 +2,14 @@ $FFFFFFE5
|
||||
$1B
|
||||
$4
|
||||
$FFFFFFFC
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$FFFFFE86
|
||||
$17A
|
||||
$0
|
||||
@@ -12,3 +20,13 @@ $0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
$0
|
||||
|
||||
@@ -2,8 +2,6 @@ warning: overflow.asm(24): [-Wdiv]
|
||||
Division of min value by -1
|
||||
warning: overflow.asm(25): [-Wdiv]
|
||||
Division of min value by -1
|
||||
warning: overflow.asm(35): [-Wshift]
|
||||
Shifting negative value -1
|
||||
warning: overflow.asm(39): [-Wlarge-constant]
|
||||
Integer constant '4294967296' is too large
|
||||
warning: overflow.asm(42): [-Wlarge-constant]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ERROR: pc-bank.asm(2):
|
||||
Source address $2a00 not in $FF00 to $FFFF
|
||||
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)!
|
||||
|
||||
@@ -6,18 +6,12 @@ warning: shift.asm(14) -> shift.asm::test(3): [-Wshift-amount]
|
||||
Shifting left by large amount 9001
|
||||
warning: shift.asm(14) -> shift.asm::test(6): [-Wshift-amount]
|
||||
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]
|
||||
Shifting left by large amount 32
|
||||
warning: shift.asm(16) -> shift.asm::test(6): [-Wshift-amount]
|
||||
Shifting left by large amount 32
|
||||
warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount]
|
||||
Shifting left by negative value: -9001
|
||||
warning: shift.asm(17) -> shift.asm::test(3): [-Wshift]
|
||||
Shifting negative value -1
|
||||
Shifting left by negative amount -9001
|
||||
warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount]
|
||||
Shifting right by large amount 9001
|
||||
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
|
||||
warning: shift.asm(23) -> shift.asm::test(6): [-Wshift]
|
||||
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]
|
||||
Shifting negative value -1
|
||||
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
|
||||
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]
|
||||
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]
|
||||
Shifting left by large amount 9001
|
||||
|
||||
Reference in New Issue
Block a user