diff --git a/Makefile b/Makefile index aa8d1ba9..fcca3cdc 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,7 @@ 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 \ @@ -61,7 +62,7 @@ rgbasm_obj := \ src/version.o 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 := \ src/link/assign.o \ diff --git a/include/asm/constexpr.h b/include/asm/constexpr.h new file mode 100644 index 00000000..c1dd21b2 --- /dev/null +++ b/include/asm/constexpr.h @@ -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 + +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 */ diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 93d6dc8b..e3a3bcdb 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -17,6 +17,7 @@ #include "asm/asm.h" #include "asm/charmap.h" +#include "asm/constexpr.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" @@ -438,10 +439,11 @@ static void updateUnion(void) char tzString[MAXSTRLEN + 1]; struct Expression sVal; int32_t nConstValue; + struct ConstExpression sConstExpr; } %type relocconst -%type const +%type const %type uconst %type const_3bit %type const_8bit @@ -453,38 +455,38 @@ static void updateUnion(void) %token T_NUMBER %token T_STRING -%left T_OP_LOGICNOT -%left 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 T_OP_ADD T_OP_SUB -%left T_OP_OR T_OP_XOR T_OP_AND -%left T_OP_SHL T_OP_SHR -%left T_OP_MUL T_OP_DIV T_OP_MOD -%left T_OP_NOT -%left T_OP_DEF -%left T_OP_BANK T_OP_ALIGN -%left T_OP_SIN -%left T_OP_COS -%left T_OP_TAN -%left T_OP_ASIN -%left T_OP_ACOS -%left T_OP_ATAN -%left T_OP_ATAN2 -%left T_OP_FDIV -%left T_OP_FMUL -%left T_OP_ROUND -%left T_OP_CEIL -%left T_OP_FLOOR +%left T_OP_LOGICNOT +%left 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 T_OP_ADD T_OP_SUB +%left T_OP_OR T_OP_XOR T_OP_AND +%left T_OP_SHL T_OP_SHR +%left T_OP_MUL T_OP_DIV T_OP_MOD +%left T_OP_NOT +%left T_OP_DEF +%left T_OP_BANK T_OP_ALIGN +%left T_OP_SIN +%left T_OP_COS +%left T_OP_TAN +%left T_OP_ASIN +%left T_OP_ACOS +%left T_OP_ATAN +%left T_OP_ATAN2 +%left T_OP_FDIV +%left T_OP_FMUL +%left T_OP_ROUND +%left T_OP_CEIL +%left T_OP_FLOOR -%token T_OP_HIGH T_OP_LOW +%token T_OP_HIGH T_OP_LOW -%left T_OP_STRCMP -%left T_OP_STRIN -%left T_OP_STRSUB -%left T_OP_STRLEN -%left T_OP_STRCAT -%left T_OP_STRUPR -%left T_OP_STRLWR +%left T_OP_STRCMP +%left T_OP_STRIN +%left T_OP_STRSUB +%left T_OP_STRLEN +%left T_OP_STRCAT +%left T_OP_STRUPR +%left T_OP_STRLWR %left NEG /* negation -- unary minus */ @@ -883,13 +885,13 @@ global_list_entry : T_ID equ : T_LABEL T_POP_EQU const { - sym_AddEqu($1, $3); + sym_AddEqu($1, constexpr_GetConstantValue(&$3)); } ; 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 { - 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)); yyerror("Error parsing charmap."); } @@ -935,28 +937,28 @@ printt : T_POP_PRINTT string printv : T_POP_PRINTV const { if (nPass == 1) - printf("$%X", $2); + printf("$%X", constexpr_GetConstantValue(&$2)); } ; printi : T_POP_PRINTI const { if (nPass == 1) - printf("%d", $2); + printf("%d", constexpr_GetConstantValue(&$2)); } ; printf : T_POP_PRINTF const { if (nPass == 1) - math_Print($2); + math_Print(constexpr_GetConstantValue(&$2)); } ; if : T_POP_IF const { nIFDepth++; - if (!$2) { + if (!constexpr_GetConstantValue(&$2)) { /* * Continue parsing after ELSE, or at ELIF or * ENDC keyword. @@ -988,7 +990,7 @@ elif : T_POP_ELIF const */ skipElif = true; - if (!$2) { + if (!constexpr_GetConstantValue(&$2)) { /* * Continue parsing after ELSE, or at * ELIF or ENDC keyword. @@ -1020,10 +1022,11 @@ endc : T_POP_ENDC 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"); else - $$ = $1 & 0x7; + $$ = value & 0x7; } ; @@ -1190,18 +1193,60 @@ relocconst : T_ID rpn_Number(&$$, sym_isConstDefined($4)); oDontExpandStrings = false; } - | T_OP_ROUND '(' const ')' { rpn_Number(&$$, math_Round($3)); } - | T_OP_CEIL '(' const ')' { rpn_Number(&$$, math_Ceil($3)); } - | T_OP_FLOOR '(' const ')' { rpn_Number(&$$, math_Floor($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_SIN '(' const ')' { rpn_Number(&$$, math_Sin($3)); } - | T_OP_COS '(' const ')' { rpn_Number(&$$, math_Cos($3)); } - | T_OP_TAN '(' const ')' { rpn_Number(&$$, math_Tan($3)); } - | T_OP_ASIN '(' const ')' { rpn_Number(&$$, math_ASin($3)); } - | T_OP_ACOS '(' const ')' { rpn_Number(&$$, math_ACos($3)); } - | T_OP_ATAN '(' const ')' { rpn_Number(&$$, math_ATan($3)); } - | T_OP_ATAN2 '(' const comma const ')' { rpn_Number(&$$, math_ATan2($3, $5)); } + | T_OP_ROUND '(' const ')' + { + rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3))); + } + | T_OP_CEIL '(' const ')' + { + rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3))); + } + | T_OP_FLOOR '(' const ')' + { + rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3))); + } + | 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 ')' { rpn_Number(&$$, strcmp($3, $5)); @@ -1221,113 +1266,79 @@ relocconst : T_ID uconst : const { - if ($1 < 0) - fatalerror("Constant mustn't be negative: %d", $1); - $$ = $1; + int32_t value = constexpr_GetConstantValue(&$1); + if (value < 0) + fatalerror("Constant mustn't be negative: %d", value); + $$ = value; } ; -const : T_ID { $$ = sym_GetConstantValue($1); } - | T_NUMBER { $$ = $1; } - | T_OP_HIGH '(' const ')' { $$ = ($3 >> 8) & 0xFF; } - | T_OP_LOW '(' const ')' { $$ = $3 & 0xFF; } +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); } | string { char *s = $1; int32_t length = charmap_Convert(&s); - $$ = str2int2(s, length); + constexpr_Number(&$$, str2int2(s, length)); free(s); } - | T_OP_LOGICNOT const %prec NEG { $$ = !$2; } - | const T_OP_LOGICOR const { $$ = $1 || $3; } - | const T_OP_LOGICAND const { $$ = $1 && $3; } - | const T_OP_LOGICEQU const { $$ = $1 == $3; } - | const T_OP_LOGICGT const { $$ = $1 > $3; } - | const T_OP_LOGICLT const { $$ = $1 < $3; } - | const T_OP_LOGICGE const { $$ = $1 >= $3; } - | const T_OP_LOGICLE const { $$ = $1 <= $3; } - | const T_OP_LOGICNE const { $$ = $1 != $3; } - | const T_OP_ADD const { $$ = $1 + $3; } - | const T_OP_SUB const { $$ = $1 - $3; } - | T_ID T_OP_SUB T_ID - { - if (sym_IsRelocDiffDefined($1, $3) == 0) - fatalerror("'%s - %s' not defined.", $1, $3); - $$ = sym_GetDefinedValue($1) - sym_GetDefinedValue($3); - } - | const T_OP_XOR const { $$ = $1 ^ $3; } - | const T_OP_OR const { $$ = $1 | $3; } - | const T_OP_AND const { $$ = $1 & $3; } - | const T_OP_SHL const - { - if ($1 < 0) - warning("Left shift of negative value: %d", $1); - - 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_SHR const - { - 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_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 ')' { - $$ = sym_isConstDefined($4); + constexpr_Number(&$$, sym_isConstDefined($4)); oDontExpandStrings = false; } | T_OP_STRCMP '(' string comma string ')' { - $$ = strcmp($3, $5); + constexpr_Number(&$$, strcmp($3, $5)); } | T_OP_STRIN '(' string comma string ')' { char *p = strstr($3, $5); if (p != NULL) - $$ = p - $3 + 1; + constexpr_Number(&$$, p - $3 + 1); else - $$ = 0; + constexpr_Number(&$$, 0); } - | T_OP_STRLEN '(' string ')' { $$ = strlen($3); } + | T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlen($3)); } | '(' const ')' { $$ = $2; } ; diff --git a/src/asm/constexpr.c b/src/asm/constexpr.c new file mode 100644 index 00000000..9acf7a28 --- /dev/null +++ b/src/asm/constexpr.c @@ -0,0 +1,231 @@ +/* + * This file is part of RGBDS. + * + * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors. + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#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; +} diff --git a/src/asm/globlex.c b/src/asm/globlex.c index b9d7e96d..b559ff3e 100644 --- a/src/asm/globlex.c +++ b/src/asm/globlex.c @@ -14,6 +14,7 @@ #include #include "asm/asm.h" +#include "asm/constexpr.h" #include "asm/lexer.h" #include "asm/main.h" #include "asm/rpn.h" diff --git a/src/asm/lexer.c b/src/asm/lexer.c index 20b6690a..09acc944 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -14,6 +14,7 @@ #include #include "asm/asm.h" +#include "asm/constexpr.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" @@ -735,6 +736,7 @@ scanagain: /* Longest match was a keyword or operator. */ pLexBuffer += pLongestFixed->nNameLength; + yylval.nConstValue = pLongestFixed->nToken; return pLongestFixed->nToken; }