mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
@@ -28,6 +28,8 @@ Other contributors
|
|||||||
|
|
||||||
- Christophe Staïesse <chastai@skynet.be>
|
- Christophe Staïesse <chastai@skynet.be>
|
||||||
|
|
||||||
|
- David Brotz <dbrotz007@gmail.com>
|
||||||
|
|
||||||
- The Musl C library <http://www.musl-libc.org>
|
- The Musl C library <http://www.musl-libc.org>
|
||||||
|
|
||||||
- obskyr <powpowd@gmail.com>
|
- obskyr <powpowd@gmail.com>
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -48,6 +48,7 @@ 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 \
|
||||||
@@ -61,7 +62,7 @@ rgbasm_obj := \
|
|||||||
src/version.o
|
src/version.o
|
||||||
|
|
||||||
src/asm/asmy.h: src/asm/asmy.c
|
src/asm/asmy.h: src/asm/asmy.c
|
||||||
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h
|
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o src/asm/constexpr.o: src/asm/asmy.h
|
||||||
|
|
||||||
rgblink_obj := \
|
rgblink_obj := \
|
||||||
src/link/assign.o \
|
src/link/assign.o \
|
||||||
|
|||||||
33
include/asm/constexpr.h
Normal file
33
include/asm/constexpr.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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_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 */
|
||||||
281
src/asm/asmy.y
281
src/asm/asmy.y
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#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"
|
||||||
@@ -438,10 +439,11 @@ static void updateUnion(void)
|
|||||||
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 <nConstValue> const
|
%type <sConstExpr> const
|
||||||
%type <nConstValue> uconst
|
%type <nConstValue> uconst
|
||||||
%type <nConstValue> const_3bit
|
%type <nConstValue> const_3bit
|
||||||
%type <sVal> const_8bit
|
%type <sVal> const_8bit
|
||||||
@@ -453,38 +455,38 @@ static void updateUnion(void)
|
|||||||
%token <nConstValue> T_NUMBER
|
%token <nConstValue> T_NUMBER
|
||||||
%token <tzString> T_STRING
|
%token <tzString> T_STRING
|
||||||
|
|
||||||
%left T_OP_LOGICNOT
|
%left <nConstValue> T_OP_LOGICNOT
|
||||||
%left T_OP_LOGICOR T_OP_LOGICAND T_OP_LOGICEQU
|
%left <nConstValue> T_OP_LOGICOR T_OP_LOGICAND T_OP_LOGICEQU
|
||||||
%left T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE
|
%left <nConstValue> T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE
|
||||||
%left T_OP_ADD T_OP_SUB
|
%left <nConstValue> T_OP_ADD T_OP_SUB
|
||||||
%left T_OP_OR T_OP_XOR T_OP_AND
|
%left <nConstValue> T_OP_OR T_OP_XOR T_OP_AND
|
||||||
%left T_OP_SHL T_OP_SHR
|
%left <nConstValue> T_OP_SHL T_OP_SHR
|
||||||
%left T_OP_MUL T_OP_DIV T_OP_MOD
|
%left <nConstValue> T_OP_MUL T_OP_DIV T_OP_MOD
|
||||||
%left T_OP_NOT
|
%left <nConstValue> T_OP_NOT
|
||||||
%left T_OP_DEF
|
%left <nConstValue> T_OP_DEF
|
||||||
%left T_OP_BANK T_OP_ALIGN
|
%left <nConstValue> T_OP_BANK T_OP_ALIGN
|
||||||
%left T_OP_SIN
|
%left <nConstValue> T_OP_SIN
|
||||||
%left T_OP_COS
|
%left <nConstValue> T_OP_COS
|
||||||
%left T_OP_TAN
|
%left <nConstValue> T_OP_TAN
|
||||||
%left T_OP_ASIN
|
%left <nConstValue> T_OP_ASIN
|
||||||
%left T_OP_ACOS
|
%left <nConstValue> T_OP_ACOS
|
||||||
%left T_OP_ATAN
|
%left <nConstValue> T_OP_ATAN
|
||||||
%left T_OP_ATAN2
|
%left <nConstValue> T_OP_ATAN2
|
||||||
%left T_OP_FDIV
|
%left <nConstValue> T_OP_FDIV
|
||||||
%left T_OP_FMUL
|
%left <nConstValue> T_OP_FMUL
|
||||||
%left T_OP_ROUND
|
%left <nConstValue> T_OP_ROUND
|
||||||
%left T_OP_CEIL
|
%left <nConstValue> T_OP_CEIL
|
||||||
%left T_OP_FLOOR
|
%left <nConstValue> T_OP_FLOOR
|
||||||
|
|
||||||
%token T_OP_HIGH T_OP_LOW
|
%token <nConstValue> T_OP_HIGH T_OP_LOW
|
||||||
|
|
||||||
%left T_OP_STRCMP
|
%left <nConstValue> T_OP_STRCMP
|
||||||
%left T_OP_STRIN
|
%left <nConstValue> T_OP_STRIN
|
||||||
%left T_OP_STRSUB
|
%left <nConstValue> T_OP_STRSUB
|
||||||
%left T_OP_STRLEN
|
%left <nConstValue> T_OP_STRLEN
|
||||||
%left T_OP_STRCAT
|
%left <nConstValue> T_OP_STRCAT
|
||||||
%left T_OP_STRUPR
|
%left <nConstValue> T_OP_STRUPR
|
||||||
%left T_OP_STRLWR
|
%left <nConstValue> T_OP_STRLWR
|
||||||
|
|
||||||
%left NEG /* negation -- unary minus */
|
%left NEG /* negation -- unary minus */
|
||||||
|
|
||||||
@@ -883,13 +885,13 @@ global_list_entry : T_ID
|
|||||||
|
|
||||||
equ : T_LABEL T_POP_EQU const
|
equ : T_LABEL T_POP_EQU const
|
||||||
{
|
{
|
||||||
sym_AddEqu($1, $3);
|
sym_AddEqu($1, constexpr_GetConstantValue(&$3));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
set : T_LABEL T_POP_SET const
|
set : T_LABEL T_POP_SET const
|
||||||
{
|
{
|
||||||
sym_AddSet($1, $3);
|
sym_AddSet($1, constexpr_GetConstantValue(&$3));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -918,7 +920,7 @@ charmap : T_POP_CHARMAP string comma string
|
|||||||
}
|
}
|
||||||
| T_POP_CHARMAP string comma const
|
| T_POP_CHARMAP string comma const
|
||||||
{
|
{
|
||||||
if (charmap_Add($2, $4 & 0xFF) == -1) {
|
if (charmap_Add($2, constexpr_GetConstantValue(&$4) & 0xFF) == -1) {
|
||||||
fprintf(stderr, "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));
|
fprintf(stderr, "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.");
|
yyerror("Error parsing charmap.");
|
||||||
}
|
}
|
||||||
@@ -935,28 +937,28 @@ printt : T_POP_PRINTT string
|
|||||||
printv : T_POP_PRINTV const
|
printv : T_POP_PRINTV const
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
if (nPass == 1)
|
||||||
printf("$%X", $2);
|
printf("$%X", constexpr_GetConstantValue(&$2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
printi : T_POP_PRINTI const
|
printi : T_POP_PRINTI const
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
if (nPass == 1)
|
||||||
printf("%d", $2);
|
printf("%d", constexpr_GetConstantValue(&$2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
printf : T_POP_PRINTF const
|
printf : T_POP_PRINTF const
|
||||||
{
|
{
|
||||||
if (nPass == 1)
|
if (nPass == 1)
|
||||||
math_Print($2);
|
math_Print(constexpr_GetConstantValue(&$2));
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
if : T_POP_IF const
|
if : T_POP_IF const
|
||||||
{
|
{
|
||||||
nIFDepth++;
|
nIFDepth++;
|
||||||
if (!$2) {
|
if (!constexpr_GetConstantValue(&$2)) {
|
||||||
/*
|
/*
|
||||||
* Continue parsing after ELSE, or at ELIF or
|
* Continue parsing after ELSE, or at ELIF or
|
||||||
* ENDC keyword.
|
* ENDC keyword.
|
||||||
@@ -988,7 +990,7 @@ elif : T_POP_ELIF const
|
|||||||
*/
|
*/
|
||||||
skipElif = true;
|
skipElif = true;
|
||||||
|
|
||||||
if (!$2) {
|
if (!constexpr_GetConstantValue(&$2)) {
|
||||||
/*
|
/*
|
||||||
* Continue parsing after ELSE, or at
|
* Continue parsing after ELSE, or at
|
||||||
* ELIF or ENDC keyword.
|
* ELIF or ENDC keyword.
|
||||||
@@ -1020,10 +1022,11 @@ endc : T_POP_ENDC
|
|||||||
|
|
||||||
const_3bit : const
|
const_3bit : const
|
||||||
{
|
{
|
||||||
if (($1 < 0) || ($1 > 7))
|
int32_t value = constexpr_GetConstantValue(&$1);
|
||||||
|
if ((value < 0) || (value > 7))
|
||||||
yyerror("Immediate value must be 3-bit");
|
yyerror("Immediate value must be 3-bit");
|
||||||
else
|
else
|
||||||
$$ = $1 & 0x7;
|
$$ = value & 0x7;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -1190,18 +1193,60 @@ relocconst : T_ID
|
|||||||
rpn_Number(&$$, sym_isConstDefined($4));
|
rpn_Number(&$$, sym_isConstDefined($4));
|
||||||
oDontExpandStrings = false;
|
oDontExpandStrings = false;
|
||||||
}
|
}
|
||||||
| T_OP_ROUND '(' const ')' { rpn_Number(&$$, math_Round($3)); }
|
| T_OP_ROUND '(' const ')'
|
||||||
| T_OP_CEIL '(' const ')' { rpn_Number(&$$, math_Ceil($3)); }
|
{
|
||||||
| T_OP_FLOOR '(' const ')' { rpn_Number(&$$, math_Floor($3)); }
|
rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3)));
|
||||||
| T_OP_FDIV '(' const comma const ')' { rpn_Number(&$$, math_Div($3, $5)); }
|
}
|
||||||
| T_OP_FMUL '(' const comma const ')' { rpn_Number(&$$, math_Mul($3, $5)); }
|
| T_OP_CEIL '(' const ')'
|
||||||
| T_OP_SIN '(' const ')' { rpn_Number(&$$, math_Sin($3)); }
|
{
|
||||||
| T_OP_COS '(' const ')' { rpn_Number(&$$, math_Cos($3)); }
|
rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3)));
|
||||||
| T_OP_TAN '(' const ')' { rpn_Number(&$$, math_Tan($3)); }
|
}
|
||||||
| T_OP_ASIN '(' const ')' { rpn_Number(&$$, math_ASin($3)); }
|
| T_OP_FLOOR '(' const ')'
|
||||||
| T_OP_ACOS '(' const ')' { rpn_Number(&$$, math_ACos($3)); }
|
{
|
||||||
| T_OP_ATAN '(' const ')' { rpn_Number(&$$, math_ATan($3)); }
|
rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3)));
|
||||||
| T_OP_ATAN2 '(' const comma const ')' { rpn_Number(&$$, math_ATan2($3, $5)); }
|
}
|
||||||
|
| T_OP_FDIV '(' const comma const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$,
|
||||||
|
math_Div(constexpr_GetConstantValue(&$3),
|
||||||
|
constexpr_GetConstantValue(&$5)));
|
||||||
|
}
|
||||||
|
| T_OP_FMUL '(' const comma const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$,
|
||||||
|
math_Mul(constexpr_GetConstantValue(&$3),
|
||||||
|
constexpr_GetConstantValue(&$5)));
|
||||||
|
}
|
||||||
|
| T_OP_SIN '(' const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$, math_Sin(constexpr_GetConstantValue(&$3)));
|
||||||
|
}
|
||||||
|
| T_OP_COS '(' const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$, math_Cos(constexpr_GetConstantValue(&$3)));
|
||||||
|
}
|
||||||
|
| T_OP_TAN '(' const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$, math_Tan(constexpr_GetConstantValue(&$3)));
|
||||||
|
}
|
||||||
|
| T_OP_ASIN '(' const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$, math_ASin(constexpr_GetConstantValue(&$3)));
|
||||||
|
}
|
||||||
|
| T_OP_ACOS '(' const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$, math_ACos(constexpr_GetConstantValue(&$3)));
|
||||||
|
}
|
||||||
|
| T_OP_ATAN '(' const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$, math_ATan(constexpr_GetConstantValue(&$3)));
|
||||||
|
}
|
||||||
|
| T_OP_ATAN2 '(' const comma const ')'
|
||||||
|
{
|
||||||
|
rpn_Number(&$$,
|
||||||
|
math_ATan2(constexpr_GetConstantValue(&$3),
|
||||||
|
constexpr_GetConstantValue(&$5)));
|
||||||
|
}
|
||||||
| T_OP_STRCMP '(' string comma string ')'
|
| T_OP_STRCMP '(' string comma string ')'
|
||||||
{
|
{
|
||||||
rpn_Number(&$$, strcmp($3, $5));
|
rpn_Number(&$$, strcmp($3, $5));
|
||||||
@@ -1221,113 +1266,79 @@ relocconst : T_ID
|
|||||||
|
|
||||||
uconst : const
|
uconst : const
|
||||||
{
|
{
|
||||||
if ($1 < 0)
|
int32_t value = constexpr_GetConstantValue(&$1);
|
||||||
fatalerror("Constant mustn't be negative: %d", $1);
|
if (value < 0)
|
||||||
$$ = $1;
|
fatalerror("Constant mustn't be negative: %d", value);
|
||||||
|
$$ = value;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
const : T_ID { $$ = sym_GetConstantValue($1); }
|
const : T_ID { constexpr_Symbol(&$$, $1); }
|
||||||
| T_NUMBER { $$ = $1; }
|
| T_NUMBER { constexpr_Number(&$$, $1); }
|
||||||
| T_OP_HIGH '(' const ')' { $$ = ($3 >> 8) & 0xFF; }
|
| T_OP_HIGH '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
| T_OP_LOW '(' const ')' { $$ = $3 & 0xFF; }
|
| T_OP_LOW '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
| string
|
| string
|
||||||
{
|
{
|
||||||
char *s = $1;
|
char *s = $1;
|
||||||
int32_t length = charmap_Convert(&s);
|
int32_t length = charmap_Convert(&s);
|
||||||
$$ = str2int2(s, length);
|
constexpr_Number(&$$, str2int2(s, length));
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
| T_OP_LOGICNOT const %prec NEG { $$ = !$2; }
|
| T_OP_LOGICNOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
|
||||||
| const T_OP_LOGICOR const { $$ = $1 || $3; }
|
| const T_OP_LOGICOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICAND const { $$ = $1 && $3; }
|
| const T_OP_LOGICAND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICEQU const { $$ = $1 == $3; }
|
| const T_OP_LOGICEQU const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICGT const { $$ = $1 > $3; }
|
| const T_OP_LOGICGT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICLT const { $$ = $1 < $3; }
|
| const T_OP_LOGICLT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICGE const { $$ = $1 >= $3; }
|
| const T_OP_LOGICGE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICLE const { $$ = $1 <= $3; }
|
| const T_OP_LOGICLE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_LOGICNE const { $$ = $1 != $3; }
|
| const T_OP_LOGICNE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_ADD const { $$ = $1 + $3; }
|
| const T_OP_ADD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_SUB const { $$ = $1 - $3; }
|
| const T_OP_SUB const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| T_ID T_OP_SUB T_ID
|
| const T_OP_XOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
{
|
| const T_OP_OR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
if (sym_IsRelocDiffDefined($1, $3) == 0)
|
| const T_OP_AND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
fatalerror("'%s - %s' not defined.", $1, $3);
|
| const T_OP_SHL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
$$ = sym_GetDefinedValue($1) - sym_GetDefinedValue($3);
|
| const T_OP_SHR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
}
|
| const T_OP_MUL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_XOR const { $$ = $1 ^ $3; }
|
| const T_OP_DIV const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_OR const { $$ = $1 | $3; }
|
| const T_OP_MOD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); }
|
||||||
| const T_OP_AND const { $$ = $1 & $3; }
|
| T_OP_ADD const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
|
||||||
| const T_OP_SHL const
|
| T_OP_SUB const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
|
||||||
{
|
| T_OP_NOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); }
|
||||||
if ($1 < 0)
|
| T_OP_ROUND '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
warning("Left shift of negative value: %d", $1);
|
| T_OP_CEIL '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
|
| T_OP_FLOOR '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
if ($3 < 0)
|
| T_OP_FDIV '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
|
||||||
fatalerror("Shift by negative value: %d", $3);
|
| T_OP_FMUL '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
|
||||||
else if ($3 >= 32)
|
| T_OP_SIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
fatalerror("Shift by too big value: %d", $3);
|
| T_OP_COS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
|
| T_OP_TAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
$$ = $1 << $3;
|
| T_OP_ASIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
}
|
| T_OP_ACOS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
| const T_OP_SHR const
|
| T_OP_ATAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); }
|
||||||
{
|
| T_OP_ATAN2 '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); }
|
||||||
if ($3 < 0)
|
|
||||||
fatalerror("Shift by negative value: %d", $3);
|
|
||||||
else if ($3 >= 32)
|
|
||||||
fatalerror("Shift by too big value: %d", $3);
|
|
||||||
|
|
||||||
$$ = $1 >> $3;
|
|
||||||
}
|
|
||||||
| const T_OP_MUL const { $$ = $1 * $3; }
|
|
||||||
| const T_OP_DIV const
|
|
||||||
{
|
|
||||||
if ($3 == 0)
|
|
||||||
fatalerror("Division by zero");
|
|
||||||
$$ = $1 / $3;
|
|
||||||
}
|
|
||||||
| const T_OP_MOD const
|
|
||||||
{
|
|
||||||
if ($3 == 0)
|
|
||||||
fatalerror("Division by zero");
|
|
||||||
$$ = $1 % $3;
|
|
||||||
}
|
|
||||||
| T_OP_ADD const %prec NEG { $$ = +$2; }
|
|
||||||
| T_OP_SUB const %prec NEG { $$ = -$2; }
|
|
||||||
| T_OP_NOT const %prec NEG { $$ = ~$2; }
|
|
||||||
| T_OP_ROUND '(' const ')' { $$ = math_Round($3); }
|
|
||||||
| T_OP_CEIL '(' const ')' { $$ = math_Ceil($3); }
|
|
||||||
| T_OP_FLOOR '(' const ')' { $$ = math_Floor($3); }
|
|
||||||
| T_OP_FDIV '(' const comma const ')' { $$ = math_Div($3,$5); }
|
|
||||||
| T_OP_FMUL '(' const comma const ')' { $$ = math_Mul($3,$5); }
|
|
||||||
| T_OP_SIN '(' const ')' { $$ = math_Sin($3); }
|
|
||||||
| T_OP_COS '(' const ')' { $$ = math_Cos($3); }
|
|
||||||
| T_OP_TAN '(' const ')' { $$ = math_Tan($3); }
|
|
||||||
| T_OP_ASIN '(' const ')' { $$ = math_ASin($3); }
|
|
||||||
| T_OP_ACOS '(' const ')' { $$ = math_ACos($3); }
|
|
||||||
| T_OP_ATAN '(' const ')' { $$ = math_ATan($3); }
|
|
||||||
| T_OP_ATAN2 '(' const comma const ')' { $$ = math_ATan2($3,$5); }
|
|
||||||
| T_OP_DEF {
|
| T_OP_DEF {
|
||||||
oDontExpandStrings = true;
|
oDontExpandStrings = true;
|
||||||
} '(' T_ID ')'
|
} '(' T_ID ')'
|
||||||
{
|
{
|
||||||
$$ = sym_isConstDefined($4);
|
constexpr_Number(&$$, sym_isConstDefined($4));
|
||||||
oDontExpandStrings = false;
|
oDontExpandStrings = false;
|
||||||
}
|
}
|
||||||
| T_OP_STRCMP '(' string comma string ')'
|
| T_OP_STRCMP '(' string comma string ')'
|
||||||
{
|
{
|
||||||
$$ = strcmp($3, $5);
|
constexpr_Number(&$$, strcmp($3, $5));
|
||||||
}
|
}
|
||||||
| T_OP_STRIN '(' string comma string ')'
|
| T_OP_STRIN '(' string comma string ')'
|
||||||
{
|
{
|
||||||
char *p = strstr($3, $5);
|
char *p = strstr($3, $5);
|
||||||
|
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
$$ = p - $3 + 1;
|
constexpr_Number(&$$, p - $3 + 1);
|
||||||
else
|
else
|
||||||
$$ = 0;
|
constexpr_Number(&$$, 0);
|
||||||
}
|
}
|
||||||
| T_OP_STRLEN '(' string ')' { $$ = strlen($3); }
|
| T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlen($3)); }
|
||||||
| '(' const ')' { $$ = $2; }
|
| '(' const ')' { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
231
src/asm/constexpr.c
Normal file
231
src/asm/constexpr.c
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* 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/rpn.h"
|
||||||
|
#include "asm/symbol.h"
|
||||||
|
|
||||||
|
#include "asmy.h"
|
||||||
|
|
||||||
|
void constexpr_Symbol(struct ConstExpression *expr, char *tzSym)
|
||||||
|
{
|
||||||
|
if (!sym_isConstant(tzSym)) {
|
||||||
|
struct sSymbol *pSym = sym_FindSymbol(tzSym);
|
||||||
|
|
||||||
|
if (pSym != NULL) {
|
||||||
|
expr->u.pSym = pSym;
|
||||||
|
expr->isSym = 1;
|
||||||
|
} else {
|
||||||
|
fatalerror("'%s' not defined", tzSym);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constexpr_Number(expr, sym_GetConstantValue(tzSym));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = -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 = value1 + value2;
|
||||||
|
break;
|
||||||
|
case T_OP_SUB:
|
||||||
|
result = value1 - 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:
|
||||||
|
if (value1 < 0)
|
||||||
|
warning("Left shift of negative value: %d",
|
||||||
|
value1);
|
||||||
|
|
||||||
|
if (value2 < 0)
|
||||||
|
fatalerror("Shift by negative value: %d",
|
||||||
|
value2);
|
||||||
|
else if (value2 >= 32)
|
||||||
|
fatalerror("Shift by too big value: %d",
|
||||||
|
value2);
|
||||||
|
|
||||||
|
result = value1 << value2;
|
||||||
|
break;
|
||||||
|
case T_OP_SHR:
|
||||||
|
if (value2 < 0)
|
||||||
|
fatalerror("Shift by negative value: %d",
|
||||||
|
value2);
|
||||||
|
else if (value2 >= 32)
|
||||||
|
fatalerror("Shift by too big value: %d",
|
||||||
|
value2);
|
||||||
|
|
||||||
|
result = value1 >> value2;
|
||||||
|
break;
|
||||||
|
case T_OP_MUL:
|
||||||
|
result = value1 * value2;
|
||||||
|
break;
|
||||||
|
case T_OP_DIV:
|
||||||
|
if (value2 == 0)
|
||||||
|
fatalerror("Division by zero");
|
||||||
|
result = value1 / value2;
|
||||||
|
break;
|
||||||
|
case T_OP_MOD:
|
||||||
|
if (value2 == 0)
|
||||||
|
fatalerror("Division by zero");
|
||||||
|
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,6 +14,7 @@
|
|||||||
#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"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#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"
|
||||||
@@ -769,6 +770,7 @@ scanagain:
|
|||||||
|
|
||||||
/* Longest match was a keyword or operator. */
|
/* Longest match was a keyword or operator. */
|
||||||
pLexBuffer += pLongestFixed->nNameLength;
|
pLexBuffer += pLongestFixed->nNameLength;
|
||||||
|
yylval.nConstValue = pLongestFixed->nToken;
|
||||||
return pLongestFixed->nToken;
|
return pLongestFixed->nToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user