summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgumi <git@gumi.ca>2020-03-28 16:56:20 -0400
committergumi <git@gumi.ca>2020-03-28 19:07:37 -0400
commit6b3d80109c2076a271a2f668ab2536814ca72d83 (patch)
tree4c6846c1f93de845c1fbd9e565718c8ac7a1b6ef
parentdd7f653b00239299cdecb7ca826c21e5957863da (diff)
downloadhercules-6b3d80109c2076a271a2f668ab2536814ca72d83.tar.gz
hercules-6b3d80109c2076a271a2f668ab2536814ca72d83.tar.bz2
hercules-6b3d80109c2076a271a2f668ab2536814ca72d83.tar.xz
hercules-6b3d80109c2076a271a2f668ab2536814ca72d83.zip
add support for binary and octal number literals
-rw-r--r--src/common/cbasetypes.h4
-rw-r--r--src/map/script.c89
2 files changed, 69 insertions, 24 deletions
diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h
index 0b5613316..3ca0c5f67 100644
--- a/src/common/cbasetypes.h
+++ b/src/common/cbasetypes.h
@@ -410,13 +410,15 @@ typedef char bool;
#define ISALPHA(c) (isalpha((unsigned char)(c)))
#define ISCNTRL(c) (iscntrl((unsigned char)(c)))
#define ISDIGIT(c) (isdigit((unsigned char)(c)))
+#define ISXDIGIT(c) (isxdigit((unsigned char)(c)))
+#define ISBDIGIT(c) ((unsigned char)(c) == '0' || (unsigned char)(c) == '1')
+#define ISODIGIT(c) ((unsigned char)(c) >= '0' && (unsigned char)(c) <= '7')
#define ISGRAPH(c) (isgraph((unsigned char)(c)))
#define ISLOWER(c) (islower((unsigned char)(c)))
#define ISPRINT(c) (isprint((unsigned char)(c)))
#define ISPUNCT(c) (ispunct((unsigned char)(c)))
#define ISSPACE(c) (isspace((unsigned char)(c)))
#define ISUPPER(c) (isupper((unsigned char)(c)))
-#define ISXDIGIT(c) (isxdigit((unsigned char)(c)))
#define TOASCII(c) (toascii((unsigned char)(c)))
#define TOLOWER(c) (tolower((unsigned char)(c)))
#define TOUPPER(c) (toupper((unsigned char)(c)))
diff --git a/src/map/script.c b/src/map/script.c
index b8a7979a7..d5e73ad65 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -1161,6 +1161,41 @@ static const char *parse_variable(const char *p)
return p;
}
+/**
+ * converts a number expression literal to an actual integer
+*/
+static long long parse_number(const char *p, char **np) {
+ long long lli = 0;
+ unsigned char radix = 10;
+
+ nullpo_retr(lli, p);
+
+ if (*p == '0' && p[1] == 'x') {
+ p += 2;
+ radix = 16; // hexadecimal
+ } else if (*p == '0' && p[1] == 'o') {
+ p += 2;
+ radix = 8; // octal
+ } else if (*p == '0' && p[1] == 'b') {
+ p += 2;
+ radix = 2; // binary
+ }
+
+ // actual parsing happens here
+ lli = strtoll(p, np, radix);
+
+ // make sure we can't underflow/overflow
+ if (lli < INT_MIN) {
+ lli = INT_MIN;
+ script->disp_warning_message("parse_number: underflow detected, capping value to INT_MIN", p);
+ } else if (lli > INT_MAX) {
+ lli = INT_MAX;
+ script->disp_warning_message("parse_number: overflow detected, capping value to INT_MAX", p);
+ }
+
+ return lli;
+}
+
/*
* Checks whether the gives string is a number literal
*
@@ -1177,24 +1212,44 @@ static const char *parse_variable(const char *p)
static bool is_number(const char *p)
{
const char *np;
- if (!p)
- return false;
- if (*p == '-' || *p == '+')
+ nullpo_retr(false, p);
+
+ if (*p == '-' || *p == '+') {
p++;
+ }
+
np = p;
+
if (*p == '0' && p[1] == 'x') {
- p+=2;
- np = p;
- // Hexadecimal
- while (ISXDIGIT(*np))
+ // Hexadecimal: 0xFFFF
+ np = p += 2;
+ while (ISXDIGIT(*np)) {
np++;
+ }
+ } else if (*p == '0' && p[1] == 'b') {
+ // Binary: 0b0001
+ np = p += 2;
+ while (ISBDIGIT(*np)) {
+ np++;
+ }
+ } else if (*p == '0' && p[1] == 'o') {
+ // Octal: 0o1500
+ np = p += 2;
+ while (ISODIGIT(*np)) {
+ np++;
+ }
} else {
- // Decimal
- while (ISDIGIT(*np))
+ // Decimal: 1234
+ while (ISDIGIT(*np)) {
np++;
+ }
}
- if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _
+
+ if (p != np && *np != '_' && !ISALPHA(*np)) {
+ // At least one digit, and next isn't a letter or _
return true;
+ }
+
return false;
}
@@ -1276,20 +1331,8 @@ static const char *parse_simpleexpr_paren(const char *p)
static const char *parse_simpleexpr_number(const char *p)
{
char *np = NULL;
- long long lli;
+ long long lli = parse_number(p, &np);
- nullpo_retr(NULL, p);
- while (*p == '0' && ISDIGIT(p[1]))
- p++; // Skip leading zeros, we don't support octal literals
-
- lli = strtoll(p, &np, 0);
- if (lli < INT_MIN) {
- lli = INT_MIN;
- script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN", p);
- } else if (lli > INT_MAX) {
- lli = INT_MAX;
- script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX", p);
- }
script->addi((int)lli); // Cast is safe, as it's already been checked for overflows
return np;