|
@@ -60,7 +60,11 @@
|
|
|
* If any of these restrictions is violated, an error is triggered.
|
|
* If any of these restrictions is violated, an error is triggered.
|
|
|
*
|
|
*
|
|
|
* Variables:
|
|
* Variables:
|
|
|
- * (empty) - the result of the operation as a string representing a decimal number
|
|
|
|
|
|
|
+ * is_error - whether there was an arithmetic error with the operation (true/false).
|
|
|
|
|
+ * (empty) - the result of the operation as a string representing a decimal number.
|
|
|
|
|
+ * If an attempt is made to access this variable after an arithmetic error,
|
|
|
|
|
+ * the variable resolution will fail, and an error will be logged including
|
|
|
|
|
+ * information about the particular arithemtic error.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
@@ -84,10 +88,11 @@ typedef int (*boolean_compute_func) (uintmax_t n1, uintmax_t n2);
|
|
|
|
|
|
|
|
struct number_instance {
|
|
struct number_instance {
|
|
|
NCDModuleInst *i;
|
|
NCDModuleInst *i;
|
|
|
|
|
+ char const *error;
|
|
|
uintmax_t value;
|
|
uintmax_t value;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-typedef int (*number_compute_func) (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out);
|
|
|
|
|
|
|
+typedef char const * (*number_compute_func) (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out);
|
|
|
|
|
|
|
|
static int compute_lesser (uintmax_t n1, uintmax_t n2)
|
|
static int compute_lesser (uintmax_t n1, uintmax_t n2)
|
|
|
{
|
|
{
|
|
@@ -119,54 +124,49 @@ static int compute_different (uintmax_t n1, uintmax_t n2)
|
|
|
return n1 != n2;
|
|
return n1 != n2;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static int compute_add (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
|
|
|
|
+static char const * compute_add (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
{
|
|
{
|
|
|
if (n1 > UINTMAX_MAX - n2) {
|
|
if (n1 > UINTMAX_MAX - n2) {
|
|
|
- ModuleLog(i, BLOG_ERROR, "addition overflow");
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return "addition overflow";
|
|
|
}
|
|
}
|
|
|
*out = n1 + n2;
|
|
*out = n1 + n2;
|
|
|
- return 1;
|
|
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static int compute_subtract (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
|
|
|
|
+static char const * compute_subtract (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
{
|
|
{
|
|
|
if (n1 < n2) {
|
|
if (n1 < n2) {
|
|
|
- ModuleLog(i, BLOG_ERROR, "subtraction underflow");
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return "subtraction underflow";
|
|
|
}
|
|
}
|
|
|
*out = n1 - n2;
|
|
*out = n1 - n2;
|
|
|
- return 1;
|
|
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static int compute_multiply (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
|
|
|
|
+static char const * compute_multiply (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
{
|
|
{
|
|
|
if (n2 != 0 && n1 > UINTMAX_MAX / n2) {
|
|
if (n2 != 0 && n1 > UINTMAX_MAX / n2) {
|
|
|
- ModuleLog(i, BLOG_ERROR, "multiplication overflow");
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return "multiplication overflow";
|
|
|
}
|
|
}
|
|
|
*out = n1 * n2;
|
|
*out = n1 * n2;
|
|
|
- return 1;
|
|
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static int compute_divide (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
|
|
|
|
+static char const * compute_divide (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
{
|
|
{
|
|
|
if (n2 == 0) {
|
|
if (n2 == 0) {
|
|
|
- ModuleLog(i, BLOG_ERROR, "division quotient is zero");
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return "division quotient is zero";
|
|
|
}
|
|
}
|
|
|
*out = n1 / n2;
|
|
*out = n1 / n2;
|
|
|
- return 1;
|
|
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static int compute_modulo (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
|
|
|
|
+static char const * compute_modulo (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
|
|
|
{
|
|
{
|
|
|
if (n2 == 0) {
|
|
if (n2 == 0) {
|
|
|
- ModuleLog(i, BLOG_ERROR, "modulo modulus is zero");
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ return "modulo modulus is zero";
|
|
|
}
|
|
}
|
|
|
*out = n1 % n2;
|
|
*out = n1 % n2;
|
|
|
- return 1;
|
|
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void new_boolean_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, boolean_compute_func cfunc)
|
|
static void new_boolean_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, boolean_compute_func cfunc)
|
|
@@ -238,9 +238,7 @@ static void new_number_templ (void *vo, NCDModuleInst *i, const struct NCDModule
|
|
|
goto fail0;
|
|
goto fail0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!cfunc(i, n1, n2, &o->value)) {
|
|
|
|
|
- goto fail0;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ o->error = cfunc(i, n1, n2, &o->value);
|
|
|
|
|
|
|
|
NCDModuleInst_Backend_Up(i);
|
|
NCDModuleInst_Backend_Up(i);
|
|
|
return;
|
|
return;
|
|
@@ -253,7 +251,16 @@ static int number_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem,
|
|
|
{
|
|
{
|
|
|
struct number_instance *o = vo;
|
|
struct number_instance *o = vo;
|
|
|
|
|
|
|
|
|
|
+ if (name == NCD_STRING_IS_ERROR) {
|
|
|
|
|
+ *out = ncd_make_boolean(mem, !!o->error, o->i->params->iparams->string_index);
|
|
|
|
|
+ return 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (name == NCD_STRING_EMPTY) {
|
|
if (name == NCD_STRING_EMPTY) {
|
|
|
|
|
+ if (o->error) {
|
|
|
|
|
+ ModuleLog(o->i, BLOG_ERROR, "%s", o->error);
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
*out = ncd_make_uintmax(mem, o->value);
|
|
*out = ncd_make_uintmax(mem, o->value);
|
|
|
return 1;
|
|
return 1;
|
|
|
}
|
|
}
|