Implement AXIS parity UI and execution baseline
This commit is contained in:
@@ -4,8 +4,39 @@
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Keep the public 648-byte object ABI stable; mutable parameter/diagnostic
|
||||
* state is held in a bounded side table owned by the single Worker writer. */
|
||||
#define META_SLOTS 4u
|
||||
#define NAMED_PARAMETER_CAPACITY 16u
|
||||
#define NAMED_PARAMETER_LENGTH 32u
|
||||
#define PENDING_ASSIGNMENTS 32u
|
||||
|
||||
typedef struct named_parameter {
|
||||
char name[NAMED_PARAMETER_LENGTH];
|
||||
double value;
|
||||
int used;
|
||||
} named_parameter;
|
||||
|
||||
typedef struct interpreter_meta {
|
||||
const sim_interpreter *owner;
|
||||
double parameters[SIM_INTERPRETER_PARAMETER_MAX + 1u];
|
||||
named_parameter named[NAMED_PARAMETER_CAPACITY];
|
||||
double coordinate_offsets[9][9];
|
||||
int coordinate_system;
|
||||
int cutter_comp;
|
||||
int cycle_mode;
|
||||
int coolant_mode;
|
||||
int selected_tool;
|
||||
double tool_length;
|
||||
uint32_t error_column;
|
||||
int32_t error_code;
|
||||
} interpreter_meta;
|
||||
|
||||
static interpreter_meta metadata[META_SLOTS];
|
||||
|
||||
static uint64_t fnv1a64(const unsigned char *bytes, size_t length) {
|
||||
uint64_t hash = UINT64_C(1469598103934665603);
|
||||
size_t index;
|
||||
@@ -16,60 +47,34 @@ static uint64_t fnv1a64(const unsigned char *bytes, size_t length) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
static interpreter_meta *meta_for(const sim_interpreter *interpreter, int create) {
|
||||
interpreter_meta *free_slot = NULL;
|
||||
size_t index;
|
||||
if (interpreter == NULL) return NULL;
|
||||
for (index = 0; index < META_SLOTS; ++index) {
|
||||
if (metadata[index].owner == interpreter) return &metadata[index];
|
||||
if (free_slot == NULL && metadata[index].owner == NULL) free_slot = &metadata[index];
|
||||
}
|
||||
if (!create || free_slot == NULL) return NULL;
|
||||
memset(free_slot, 0, sizeof(*free_slot));
|
||||
free_slot->owner = interpreter;
|
||||
return free_slot;
|
||||
}
|
||||
|
||||
static void meta_reset(interpreter_meta *meta, const sim_interpreter *owner) {
|
||||
memset(meta, 0, sizeof(*meta));
|
||||
meta->owner = owner;
|
||||
}
|
||||
|
||||
static int finite_state(const sim_interpreter_state *state) {
|
||||
const double *values;
|
||||
size_t index;
|
||||
if (state == 0) return 0;
|
||||
if (state == NULL) return 0;
|
||||
values = &state->x;
|
||||
for (index = 0; index < 11; ++index) if (!isfinite(values[index])) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int parse_number(const char **cursor, const char *end, double *output) {
|
||||
const char *start = *cursor;
|
||||
int sign = 1;
|
||||
int digits = 0;
|
||||
int exponent_sign = 1;
|
||||
int exponent = 0;
|
||||
long double value = 0.0L;
|
||||
long double scale = 1.0L;
|
||||
if (*cursor < end && (**cursor == '+' || **cursor == '-')) {
|
||||
if (**cursor == '-') sign = -1;
|
||||
++*cursor;
|
||||
}
|
||||
while (*cursor < end && isdigit((unsigned char)**cursor)) {
|
||||
value = value * 10.0L + (long double)(**cursor - '0');
|
||||
++*cursor;
|
||||
digits = 1;
|
||||
}
|
||||
if (*cursor < end && **cursor == '.') {
|
||||
++*cursor;
|
||||
while (*cursor < end && isdigit((unsigned char)**cursor)) {
|
||||
value = value * 10.0L + (long double)(**cursor - '0');
|
||||
scale *= 10.0L;
|
||||
++*cursor;
|
||||
digits = 1;
|
||||
}
|
||||
}
|
||||
if (!digits) { *cursor = start; return SIM_INTERP_ERR_SYNTAX; }
|
||||
if (*cursor < end && (**cursor == 'e' || **cursor == 'E')) {
|
||||
++*cursor;
|
||||
if (*cursor < end && (**cursor == '+' || **cursor == '-')) {
|
||||
if (**cursor == '-') exponent_sign = -1;
|
||||
++*cursor;
|
||||
}
|
||||
if (*cursor == end || !isdigit((unsigned char)**cursor)) { *cursor = start; return SIM_INTERP_ERR_SYNTAX; }
|
||||
while (*cursor < end && isdigit((unsigned char)**cursor)) {
|
||||
if (exponent < 10000) exponent = exponent * 10 + (**cursor - '0');
|
||||
++*cursor;
|
||||
}
|
||||
}
|
||||
value = (long double)sign * value / scale;
|
||||
if (exponent) value *= powl(10.0L, (long double)(exponent_sign * exponent));
|
||||
*output = (double)value;
|
||||
return isfinite(*output) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
|
||||
static int code_is(double value, int integer_code) {
|
||||
return isfinite(value) && fabs(value - (double)integer_code) <= 1e-12;
|
||||
}
|
||||
@@ -83,175 +88,430 @@ static int axis_index(char letter) {
|
||||
}
|
||||
}
|
||||
|
||||
static double *axis_pointer(sim_interpreter_state *state, int index) {
|
||||
return &state->x + index;
|
||||
static double *axis_pointer(sim_interpreter_state *state, int index) { return &state->x + index; }
|
||||
|
||||
static void set_error(sim_interpreter *interpreter, interpreter_meta *meta, int code, uint32_t column) {
|
||||
if (interpreter != NULL) interpreter->state.status = code;
|
||||
if (meta != NULL) { meta->error_code = code; meta->error_column = column; }
|
||||
}
|
||||
|
||||
static int apply_g(sim_interpreter_state *state, double code, int *groups) {
|
||||
static int parse_decimal(const char **cursor, const char *end, double *output) {
|
||||
const char *start = *cursor;
|
||||
int sign = 1, digits = 0, exponent_sign = 1, exponent = 0;
|
||||
long double value = 0.0L, scale = 1.0L;
|
||||
if (*cursor < end && (**cursor == '+' || **cursor == '-')) {
|
||||
if (**cursor == '-') sign = -1;
|
||||
++*cursor;
|
||||
}
|
||||
while (*cursor < end && isdigit((unsigned char)**cursor)) {
|
||||
value = value * 10.0L + (long double)(**cursor - '0'); ++*cursor; digits = 1;
|
||||
}
|
||||
if (*cursor < end && **cursor == '.') {
|
||||
++*cursor;
|
||||
while (*cursor < end && isdigit((unsigned char)**cursor)) {
|
||||
value = value * 10.0L + (long double)(**cursor - '0'); scale *= 10.0L; ++*cursor; digits = 1;
|
||||
}
|
||||
}
|
||||
if (!digits) { *cursor = start; return SIM_INTERP_ERR_SYNTAX; }
|
||||
if (*cursor < end && (**cursor == 'e' || **cursor == 'E')) {
|
||||
++*cursor;
|
||||
if (*cursor < end && (**cursor == '+' || **cursor == '-')) { if (**cursor == '-') exponent_sign = -1; ++*cursor; }
|
||||
if (*cursor == end || !isdigit((unsigned char)**cursor)) { *cursor = start; return SIM_INTERP_ERR_SYNTAX; }
|
||||
while (*cursor < end && isdigit((unsigned char)**cursor)) { if (exponent < 10000) exponent = exponent * 10 + (**cursor - '0'); ++*cursor; }
|
||||
}
|
||||
value = (long double)sign * value / scale;
|
||||
if (exponent != 0) value *= powl(10.0L, (long double)(exponent_sign * exponent));
|
||||
*output = (double)value;
|
||||
return isfinite(*output) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
|
||||
typedef struct expression_parser {
|
||||
interpreter_meta *meta;
|
||||
const char *cursor;
|
||||
const char *end;
|
||||
int pending_index[PENDING_ASSIGNMENTS];
|
||||
double pending_value[PENDING_ASSIGNMENTS];
|
||||
size_t pending_count;
|
||||
} expression_parser;
|
||||
|
||||
static void skip_space(expression_parser *parser) {
|
||||
while (parser->cursor < parser->end && isspace((unsigned char)*parser->cursor)) ++parser->cursor;
|
||||
}
|
||||
|
||||
static int identifier(expression_parser *parser, char *buffer, size_t capacity) {
|
||||
size_t length = 0;
|
||||
skip_space(parser);
|
||||
while (parser->cursor < parser->end && isalpha((unsigned char)*parser->cursor)) {
|
||||
if (length + 1u < capacity) buffer[length++] = (char)toupper((unsigned char)*parser->cursor);
|
||||
++parser->cursor;
|
||||
}
|
||||
buffer[length] = '\0';
|
||||
return length > 0 ? SIM_INTERP_OK : SIM_INTERP_ERR_SYNTAX;
|
||||
}
|
||||
|
||||
static uint32_t named_hash(const char *name) { return (uint32_t)(fnv1a64((const unsigned char *)name, strlen(name)) & UINT32_C(0x7fffffff)); }
|
||||
|
||||
static int parameter_lookup(const expression_parser *parser, uint32_t index, double *value) {
|
||||
size_t item;
|
||||
if (index < SIM_INTERPRETER_PARAMETER_MIN || index > SIM_INTERPRETER_PARAMETER_MAX || value == NULL) return SIM_INTERP_ERR_PARAMETER;
|
||||
for (item = parser->pending_count; item > 0; --item) {
|
||||
if ((uint32_t)parser->pending_index[item - 1u] == index) { *value = parser->pending_value[item - 1u]; return SIM_INTERP_OK; }
|
||||
}
|
||||
*value = parser->meta->parameters[index];
|
||||
return isfinite(*value) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
|
||||
static int named_lookup(expression_parser *parser, const char *name, double *value, int create) {
|
||||
size_t index;
|
||||
if (name == NULL || name[0] == '\0' || value == NULL) return SIM_INTERP_ERR_PARAMETER;
|
||||
for (index = 0; index < NAMED_PARAMETER_CAPACITY; ++index) {
|
||||
if (parser->meta->named[index].used && strcmp(parser->meta->named[index].name, name) == 0) { *value = parser->meta->named[index].value; return SIM_INTERP_OK; }
|
||||
}
|
||||
if (!create) { *value = 0.0; return SIM_INTERP_OK; }
|
||||
for (index = 0; index < NAMED_PARAMETER_CAPACITY; ++index) if (!parser->meta->named[index].used) {
|
||||
strncpy(parser->meta->named[index].name, name, NAMED_PARAMETER_LENGTH - 1u);
|
||||
parser->meta->named[index].name[NAMED_PARAMETER_LENGTH - 1u] = '\0';
|
||||
parser->meta->named[index].used = 1; parser->meta->named[index].value = 0.0; *value = 0.0; return SIM_INTERP_OK;
|
||||
}
|
||||
return SIM_INTERP_ERR_PARAMETER;
|
||||
}
|
||||
|
||||
static int parse_expression(expression_parser *parser, double *value);
|
||||
|
||||
static int parse_parameter_reference(expression_parser *parser, double *value, int *named_slot) {
|
||||
unsigned long index = 0;
|
||||
char name[NAMED_PARAMETER_LENGTH] = {0};
|
||||
size_t length = 0;
|
||||
int result;
|
||||
skip_space(parser);
|
||||
if (parser->cursor >= parser->end || *parser->cursor != '#') return SIM_INTERP_ERR_SYNTAX;
|
||||
++parser->cursor;
|
||||
if (parser->cursor < parser->end && *parser->cursor == '<') {
|
||||
++parser->cursor;
|
||||
while (parser->cursor < parser->end && *parser->cursor != '>') {
|
||||
if (length + 1u < sizeof(name)) name[length++] = (char)tolower((unsigned char)*parser->cursor);
|
||||
++parser->cursor;
|
||||
}
|
||||
if (parser->cursor >= parser->end || *parser->cursor != '>' || length == 0) return SIM_INTERP_ERR_PARAMETER;
|
||||
++parser->cursor; name[length] = '\0';
|
||||
result = named_lookup(parser, name, value, 1);
|
||||
if (named_slot != NULL) *named_slot = (int)named_hash(name);
|
||||
return result;
|
||||
}
|
||||
if (parser->cursor < parser->end && *parser->cursor == '[') {
|
||||
double expression_value;
|
||||
++parser->cursor; result = parse_expression(parser, &expression_value); skip_space(parser);
|
||||
if (result != SIM_INTERP_OK || parser->cursor >= parser->end || *parser->cursor != ']') return SIM_INTERP_ERR_PARAMETER;
|
||||
++parser->cursor;
|
||||
if (!isfinite(expression_value) || expression_value < 1.0 || expression_value > (double)SIM_INTERPRETER_PARAMETER_MAX || floor(expression_value) != expression_value) return SIM_INTERP_ERR_PARAMETER;
|
||||
index = (unsigned long)expression_value;
|
||||
} else {
|
||||
const char *start = parser->cursor;
|
||||
while (parser->cursor < parser->end && isdigit((unsigned char)*parser->cursor)) { if (index <= 1000000UL) index = index * 10UL + (unsigned long)(*parser->cursor - '0'); ++parser->cursor; }
|
||||
if (parser->cursor == start || index < SIM_INTERPRETER_PARAMETER_MIN || index > SIM_INTERPRETER_PARAMETER_MAX) return SIM_INTERP_ERR_PARAMETER;
|
||||
}
|
||||
if (named_slot != NULL) *named_slot = 0;
|
||||
return parameter_lookup(parser, (uint32_t)index, value);
|
||||
}
|
||||
|
||||
static int parse_primary(expression_parser *parser, double *value) {
|
||||
char function_name[16] = {0};
|
||||
const char *start;
|
||||
int result;
|
||||
skip_space(parser);
|
||||
if (parser->cursor >= parser->end) return SIM_INTERP_ERR_EXPRESSION;
|
||||
if (*parser->cursor == '#') return parse_parameter_reference(parser, value, NULL);
|
||||
if (*parser->cursor == '[') {
|
||||
++parser->cursor; result = parse_expression(parser, value); skip_space(parser);
|
||||
if (result != SIM_INTERP_OK || parser->cursor >= parser->end || *parser->cursor != ']') return SIM_INTERP_ERR_EXPRESSION;
|
||||
++parser->cursor; return isfinite(*value) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
if (isalpha((unsigned char)*parser->cursor)) {
|
||||
result = identifier(parser, function_name, sizeof(function_name)); if (result != SIM_INTERP_OK) return result;
|
||||
skip_space(parser);
|
||||
if (strcmp(function_name, "PI") == 0) { *value = 3.14159265358979323846; return SIM_INTERP_OK; }
|
||||
if (strcmp(function_name, "E") == 0) { *value = 2.71828182845904523536; return SIM_INTERP_OK; }
|
||||
if (strcmp(function_name, "NAN") == 0 || strcmp(function_name, "INF") == 0 || strcmp(function_name, "INFINITY") == 0) return SIM_INTERP_ERR_SYNTAX;
|
||||
if (strcmp(function_name, "MOD") == 0) return SIM_INTERP_ERR_EXPRESSION;
|
||||
if (parser->cursor < parser->end && *parser->cursor == '[') {
|
||||
++parser->cursor; result = parse_expression(parser, value); skip_space(parser);
|
||||
if (result != SIM_INTERP_OK || parser->cursor >= parser->end || *parser->cursor != ']') return SIM_INTERP_ERR_EXPRESSION;
|
||||
++parser->cursor;
|
||||
} else { result = parse_primary(parser, value); if (result != SIM_INTERP_OK) return result; }
|
||||
if (!isfinite(*value)) return SIM_INTERP_ERR_NONFINITE;
|
||||
if (strcmp(function_name, "ABS") == 0) *value = fabs(*value);
|
||||
else if (strcmp(function_name, "SQRT") == 0) { if (*value < 0.0) return SIM_INTERP_ERR_RANGE; *value = sqrt(*value); }
|
||||
else if (strcmp(function_name, "SIN") == 0) *value = sin(*value * 3.14159265358979323846 / 180.0);
|
||||
else if (strcmp(function_name, "COS") == 0) *value = cos(*value * 3.14159265358979323846 / 180.0);
|
||||
else if (strcmp(function_name, "TAN") == 0) *value = tan(*value * 3.14159265358979323846 / 180.0);
|
||||
else if (strcmp(function_name, "ASIN") == 0) { if (fabs(*value) > 1.0) return SIM_INTERP_ERR_RANGE; *value = asin(*value) * 180.0 / 3.14159265358979323846; }
|
||||
else if (strcmp(function_name, "ACOS") == 0) { if (fabs(*value) > 1.0) return SIM_INTERP_ERR_RANGE; *value = acos(*value) * 180.0 / 3.14159265358979323846; }
|
||||
else if (strcmp(function_name, "ATAN") == 0) *value = atan(*value) * 180.0 / 3.14159265358979323846;
|
||||
else if (strcmp(function_name, "FIX") == 0) *value = floor(*value);
|
||||
else if (strcmp(function_name, "FUP") == 0) *value = ceil(*value);
|
||||
else if (strcmp(function_name, "ROUND") == 0) *value = nearbyint(*value);
|
||||
else if (strcmp(function_name, "EXP") == 0) *value = exp(*value);
|
||||
else if (strcmp(function_name, "LN") == 0) { if (*value <= 0.0) return SIM_INTERP_ERR_RANGE; *value = log(*value); }
|
||||
else return SIM_INTERP_ERR_UNKNOWN_CODE;
|
||||
return isfinite(*value) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
start = parser->cursor; result = parse_decimal(&parser->cursor, parser->end, value); if (result != SIM_INTERP_OK) parser->cursor = start;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int parse_unary(expression_parser *parser, double *value) {
|
||||
skip_space(parser);
|
||||
if (parser->cursor < parser->end && (*parser->cursor == '+' || *parser->cursor == '-')) {
|
||||
char sign = *parser->cursor++; int result = parse_unary(parser, value);
|
||||
if (result == SIM_INTERP_OK && sign == '-') *value = -*value; return result;
|
||||
}
|
||||
return parse_primary(parser, value);
|
||||
}
|
||||
|
||||
static int parse_power(expression_parser *parser, double *value) {
|
||||
int result = parse_unary(parser, value); skip_space(parser); if (result != SIM_INTERP_OK) return result;
|
||||
if (parser->cursor + 1 < parser->end && parser->cursor[0] == '*' && parser->cursor[1] == '*') {
|
||||
double right; parser->cursor += 2; result = parse_power(parser, &right); if (result != SIM_INTERP_OK) return result; *value = pow(*value, right);
|
||||
}
|
||||
return isfinite(*value) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
|
||||
static int parse_product(expression_parser *parser, double *value) {
|
||||
int result = parse_power(parser, value); if (result != SIM_INTERP_OK) return result;
|
||||
for (;;) {
|
||||
double right; char operator_name[8] = {0}; const char *save;
|
||||
skip_space(parser);
|
||||
if (parser->cursor >= parser->end || (*parser->cursor != '*' && *parser->cursor != '/')) {
|
||||
save = parser->cursor;
|
||||
if (parser->cursor < parser->end && isalpha((unsigned char)*parser->cursor)) { identifier(parser, operator_name, sizeof(operator_name)); if (strcmp(operator_name, "MOD") != 0) parser->cursor = save; }
|
||||
if (strcmp(operator_name, "MOD") != 0) break;
|
||||
}
|
||||
if (operator_name[0] != '\0') result = parse_power(parser, &right);
|
||||
else {
|
||||
char operator_character = *parser->cursor++; result = parse_power(parser, &right);
|
||||
if (result == SIM_INTERP_OK) { if (operator_character == '/' && right == 0.0) result = SIM_INTERP_ERR_RANGE; else if (operator_character == '*') *value *= right; else *value /= right; }
|
||||
}
|
||||
if (strcmp(operator_name, "MOD") == 0 && result == SIM_INTERP_OK) { if (right == 0.0) result = SIM_INTERP_ERR_RANGE; else *value = fmod(*value, right); }
|
||||
if (result != SIM_INTERP_OK) return result;
|
||||
}
|
||||
return isfinite(*value) ? SIM_INTERP_OK : SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
|
||||
static int parse_expression(expression_parser *parser, double *value) {
|
||||
int result = parse_product(parser, value); if (result != SIM_INTERP_OK) return result;
|
||||
for (;;) {
|
||||
char operator_character; double right; skip_space(parser);
|
||||
if (parser->cursor >= parser->end || (*parser->cursor != '+' && *parser->cursor != '-')) break;
|
||||
operator_character = *parser->cursor++; result = parse_product(parser, &right); if (result != SIM_INTERP_OK) return result;
|
||||
if (operator_character == '+') *value += right; else *value -= right; if (!isfinite(*value)) return SIM_INTERP_ERR_NONFINITE;
|
||||
}
|
||||
return SIM_INTERP_OK;
|
||||
}
|
||||
|
||||
static int apply_g(sim_interpreter_state *state, interpreter_meta *meta, double code, int *groups) {
|
||||
if (code_is(code, 0)) { if (++groups[0] > 1) return SIM_INTERP_ERR_STATE; state->motion_mode = 0; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 1)) { if (++groups[0] > 1) return SIM_INTERP_ERR_STATE; state->motion_mode = 1; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 2) || code_is(code, 3)) { if (++groups[0] > 1) return SIM_INTERP_ERR_STATE; state->motion_mode = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 17) || code_is(code, 18) || code_is(code, 19)) { if (++groups[1] > 1) return SIM_INTERP_ERR_STATE; state->plane = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 20) || code_is(code, 21)) { if (++groups[2] > 1) return SIM_INTERP_ERR_STATE; state->units = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 90) || code_is(code, 91)) { if (++groups[3] > 1) return SIM_INTERP_ERR_STATE; state->distance_mode = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 40) || code_is(code, 41) || code_is(code, 42)) { if (++groups[4] > 1) return SIM_INTERP_ERR_STATE; if (meta) meta->cutter_comp = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 43) || code_is(code, 49)) { if (++groups[5] > 1) return SIM_INTERP_ERR_STATE; if (meta && code_is(code, 49)) meta->tool_length = 0.0; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 80) || (code >= 81.0 && code <= 89.0 && floor(code) == code)) { if (meta) meta->cycle_mode = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 54) || code_is(code, 55) || code_is(code, 56) || code_is(code, 57) || code_is(code, 58) || code_is(code, 59)) { if (meta) meta->coordinate_system = (int)code - 53; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 10)) return SIM_INTERP_OK;
|
||||
return SIM_INTERP_ERR_UNKNOWN_CODE;
|
||||
}
|
||||
|
||||
static int apply_m(sim_interpreter_state *state, double code, int *groups) {
|
||||
if (code_is(code, 3) || code_is(code, 4) || code_is(code, 5)) {
|
||||
if (++groups[4] > 1) return SIM_INTERP_ERR_STATE;
|
||||
state->spindle_mode = (int)code;
|
||||
return SIM_INTERP_OK;
|
||||
}
|
||||
if (code_is(code, 2) || code_is(code, 30)) {
|
||||
if (++groups[5] > 1) return SIM_INTERP_ERR_STATE;
|
||||
state->program_end = 1;
|
||||
return SIM_INTERP_OK;
|
||||
}
|
||||
static int apply_m(sim_interpreter_state *state, interpreter_meta *meta, double code, int *groups) {
|
||||
if (code_is(code, 3) || code_is(code, 4) || code_is(code, 5)) { if (++groups[4] > 1) return SIM_INTERP_ERR_STATE; state->spindle_mode = (int)code; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 2) || code_is(code, 30)) { if (++groups[5] > 1) return SIM_INTERP_ERR_STATE; state->program_end = 1; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 6)) { if (meta) meta->selected_tool = meta->selected_tool < 0 ? 0 : meta->selected_tool; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 7)) { if (meta) meta->coolant_mode = 7; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 8)) { if (meta) meta->coolant_mode = 8; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 9)) { if (meta) meta->coolant_mode = 0; return SIM_INTERP_OK; }
|
||||
if (code_is(code, 19)) return SIM_INTERP_OK;
|
||||
if (code_is(code, 48) || code_is(code, 49) || code_is(code, 50) || code_is(code, 51) || code_is(code, 52) || code_is(code, 53)) return SIM_INTERP_OK;
|
||||
if (code >= 62.0 && code <= 68.0 && floor(code) == code) return SIM_INTERP_OK;
|
||||
if (code_is(code, 70) || code_is(code, 71) || code_is(code, 72) || code_is(code, 73)) return SIM_INTERP_OK;
|
||||
return SIM_INTERP_ERR_UNKNOWN_CODE;
|
||||
}
|
||||
|
||||
static uint64_t state_hash(const sim_interpreter_state *state) {
|
||||
unsigned char bytes[sizeof(double) * 11 + sizeof(uint32_t) + sizeof(int) * 7];
|
||||
size_t offset = 0;
|
||||
const double *values = &state->x;
|
||||
size_t index;
|
||||
static uint64_t state_hash(const sim_interpreter *interpreter) {
|
||||
unsigned char bytes[sizeof(double) * 11 + sizeof(uint32_t) + sizeof(int) * 7 + sizeof(uint64_t)];
|
||||
size_t offset = 0, index; uint64_t parameter_hash = 0;
|
||||
const double *values = &interpreter->state.x; interpreter_meta *meta = meta_for(interpreter, 0);
|
||||
for (index = 0; index < 11; ++index) { memcpy(bytes + offset, values + index, sizeof(double)); offset += sizeof(double); }
|
||||
memcpy(bytes + offset, &state->line, sizeof(uint32_t)); offset += sizeof(uint32_t);
|
||||
memcpy(bytes + offset, &state->units, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &state->distance_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &state->plane, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &state->motion_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &state->spindle_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &state->program_end, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &state->status, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.line, sizeof(uint32_t)); offset += sizeof(uint32_t);
|
||||
memcpy(bytes + offset, &interpreter->state.units, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.distance_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.plane, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.motion_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.spindle_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.program_end, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.status, sizeof(int)); offset += sizeof(int);
|
||||
if (meta != NULL) {
|
||||
parameter_hash = fnv1a64((const unsigned char *)meta->parameters, sizeof(meta->parameters));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)meta->coordinate_offsets, sizeof(meta->coordinate_offsets));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)&meta->coordinate_system, sizeof(meta->coordinate_system));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)&meta->cutter_comp, sizeof(meta->cutter_comp));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)&meta->cycle_mode, sizeof(meta->cycle_mode));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)&meta->coolant_mode, sizeof(meta->coolant_mode));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)&meta->selected_tool, sizeof(meta->selected_tool));
|
||||
parameter_hash ^= fnv1a64((const unsigned char *)&meta->tool_length, sizeof(meta->tool_length));
|
||||
}
|
||||
memcpy(bytes + offset, ¶meter_hash, sizeof(parameter_hash)); offset += sizeof(parameter_hash);
|
||||
return fnv1a64(bytes, offset);
|
||||
}
|
||||
|
||||
static uint64_t modal_hash(const sim_interpreter *interpreter) {
|
||||
unsigned char bytes[sizeof(int) * 10 + sizeof(double) * 3]; size_t offset = 0;
|
||||
memcpy(bytes + offset, &interpreter->state.units, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.distance_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.plane, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.motion_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.spindle_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &interpreter->state.feed, sizeof(double)); offset += sizeof(double);
|
||||
memcpy(bytes + offset, &interpreter->state.speed, sizeof(double)); offset += sizeof(double);
|
||||
{
|
||||
interpreter_meta *meta = meta_for(interpreter, 0);
|
||||
if (meta != NULL) {
|
||||
memcpy(bytes + offset, &meta->coordinate_system, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &meta->cutter_comp, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &meta->cycle_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &meta->coolant_mode, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &meta->selected_tool, sizeof(int)); offset += sizeof(int);
|
||||
memcpy(bytes + offset, &meta->tool_length, sizeof(double)); offset += sizeof(double);
|
||||
}
|
||||
}
|
||||
return fnv1a64(bytes, offset);
|
||||
}
|
||||
|
||||
static int make_canonical(sim_interpreter *interpreter) {
|
||||
int written;
|
||||
const sim_interpreter_state *s = &interpreter->state;
|
||||
int written; const sim_interpreter_state *s = &interpreter->state;
|
||||
written = snprintf(interpreter->canonical, sizeof(interpreter->canonical),
|
||||
"{\"a\":%.17g,\"b\":%.17g,\"c\":%.17g,\"distance_mode\":%d,\"feed\":%.17g,\"line\":%u,\"motion_mode\":%d,\"plane\":%d,\"program_end\":%d,\"speed\":%.17g,\"spindle_mode\":%d,\"status\":%d,\"units\":%d,\"u\":%.17g,\"v\":%.17g,\"w\":%.17g,\"x\":%.17g,\"y\":%.17g,\"z\":%.17g}",
|
||||
s->a, s->b, s->c, s->distance_mode, s->feed, s->line, s->motion_mode, s->plane, s->program_end,
|
||||
"{\"a\":%.17g,\"b\":%.17g,\"c\":%.17g,\"distance_mode\":%d,\"feed\":%.17g,\"line\":%u,\"modal_hash\":%llu,\"motion_mode\":%d,\"plane\":%d,\"program_end\":%d,\"speed\":%.17g,\"spindle_mode\":%d,\"status\":%d,\"units\":%d,\"u\":%.17g,\"v\":%.17g,\"w\":%.17g,\"x\":%.17g,\"y\":%.17g,\"z\":%.17g}",
|
||||
s->a, s->b, s->c, s->distance_mode, s->feed, s->line, (unsigned long long)modal_hash(interpreter), s->motion_mode, s->plane, s->program_end,
|
||||
s->speed, s->spindle_mode, s->status, s->units, s->u, s->v, s->w, s->x, s->y, s->z);
|
||||
if (written < 0 || (size_t)written >= sizeof(interpreter->canonical)) return SIM_INTERP_ERR_BUFFER;
|
||||
interpreter->canonical_length = (uint32_t)written;
|
||||
return SIM_INTERP_OK;
|
||||
interpreter->canonical_length = (uint32_t)written; return SIM_INTERP_OK;
|
||||
}
|
||||
|
||||
uint32_t sim_interpreter_size(void) { return (uint32_t)sizeof(sim_interpreter); }
|
||||
|
||||
int sim_interpreter_reset(sim_interpreter *interpreter) {
|
||||
if (interpreter == 0) return SIM_INTERP_ERR_ARGUMENT;
|
||||
memset(interpreter, 0, sizeof(*interpreter));
|
||||
interpreter->state.units = SIM_INTERP_UNITS_MM;
|
||||
interpreter->state.distance_mode = SIM_INTERP_ABSOLUTE;
|
||||
interpreter->state.plane = 17;
|
||||
interpreter->state.motion_mode = 1;
|
||||
interpreter->state.spindle_mode = 5;
|
||||
interpreter->state.status = SIM_INTERP_OK;
|
||||
interpreter_meta *meta;
|
||||
if (interpreter == NULL) return SIM_INTERP_ERR_ARGUMENT;
|
||||
memset(interpreter, 0, sizeof(*interpreter)); meta = meta_for(interpreter, 1); if (meta == NULL) return SIM_INTERP_ERR_BUFFER; meta_reset(meta, interpreter);
|
||||
interpreter->state.units = SIM_INTERP_UNITS_MM; interpreter->state.distance_mode = SIM_INTERP_ABSOLUTE; interpreter->state.plane = 17; interpreter->state.motion_mode = 1; interpreter->state.spindle_mode = 5; interpreter->state.status = SIM_INTERP_OK;
|
||||
return make_canonical(interpreter);
|
||||
}
|
||||
|
||||
int sim_interpreter_init(sim_interpreter *interpreter) {
|
||||
return sim_interpreter_reset(interpreter);
|
||||
}
|
||||
int sim_interpreter_init(sim_interpreter *interpreter) { return sim_interpreter_reset(interpreter); }
|
||||
|
||||
int sim_interpreter_execute(sim_interpreter *interpreter, const char *block, uint32_t length) {
|
||||
sim_interpreter_state next;
|
||||
const char *cursor;
|
||||
const char *end;
|
||||
int groups[6] = {0};
|
||||
int seen_axis[9] = {0};
|
||||
double axis_values[9] = {0};
|
||||
int seen_feed = 0;
|
||||
int seen_speed = 0;
|
||||
double feed_value = 0.0;
|
||||
double speed_value = 0.0;
|
||||
int seen_line = 0;
|
||||
int result = SIM_INTERP_OK;
|
||||
if (interpreter == 0 || block == 0 || length == 0) return SIM_INTERP_ERR_ARGUMENT;
|
||||
if (!finite_state(&interpreter->state)) return SIM_INTERP_ERR_STATE;
|
||||
if (interpreter->state.program_end) return SIM_INTERP_ERR_STATE;
|
||||
next = interpreter->state;
|
||||
cursor = block;
|
||||
end = block + length;
|
||||
while (cursor < end) {
|
||||
char letter;
|
||||
double value;
|
||||
int index;
|
||||
while (cursor < end && isspace((unsigned char)*cursor)) ++cursor;
|
||||
if (cursor >= end) break;
|
||||
if (*cursor == ';') break;
|
||||
if (*cursor == '(') {
|
||||
int closed = 0;
|
||||
++cursor;
|
||||
while (cursor < end) { if (*cursor++ == ')') { closed = 1; break; } }
|
||||
if (!closed) return SIM_INTERP_ERR_SYNTAX;
|
||||
sim_interpreter_state next; interpreter_meta *meta; expression_parser parser; const char *end;
|
||||
int groups[6] = {0}, seen_axis[9] = {0}, seen_feed = 0, seen_speed = 0, seen_line = 0, seen_p = 0, seen_r = 0, seen_g10 = 0, result = SIM_INTERP_OK;
|
||||
double axis_values[9] = {0}, feed_value = 0.0, speed_value = 0.0, p_value = 0.0, r_value = 0.0;
|
||||
if (interpreter == NULL || block == NULL || length == 0) return SIM_INTERP_ERR_ARGUMENT;
|
||||
meta = meta_for(interpreter, 1); if (meta == NULL || !finite_state(&interpreter->state)) return SIM_INTERP_ERR_STATE;
|
||||
if (interpreter->state.program_end) { set_error(interpreter, meta, SIM_INTERP_ERR_STATE, 1); return SIM_INTERP_ERR_STATE; }
|
||||
next = interpreter->state; parser.meta = meta; parser.cursor = block; parser.end = block + length; parser.pending_count = 0; end = parser.end;
|
||||
while (parser.cursor < end) {
|
||||
char letter; double value; int index; uint32_t column;
|
||||
while (parser.cursor < end && isspace((unsigned char)*parser.cursor)) ++parser.cursor;
|
||||
if (parser.cursor >= end || *parser.cursor == ';') break;
|
||||
if (*parser.cursor == '%') { ++parser.cursor; continue; }
|
||||
if (*parser.cursor == '(') {
|
||||
int closed = 0; ++parser.cursor; while (parser.cursor < end) { if (*parser.cursor++ == ')') { closed = 1; break; } }
|
||||
if (!closed) { set_error(interpreter, meta, SIM_INTERP_ERR_SYNTAX, (uint32_t)(parser.cursor - block)); return SIM_INTERP_ERR_SYNTAX; }
|
||||
continue;
|
||||
}
|
||||
letter = (char)toupper((unsigned char)*cursor++);
|
||||
if (letter == '%') continue;
|
||||
if (letter < 'A' || letter > 'Z') return SIM_INTERP_ERR_SYNTAX;
|
||||
result = parse_number(&cursor, end, &value);
|
||||
if (result != SIM_INTERP_OK) return result;
|
||||
if (*parser.cursor == '#') {
|
||||
const char *assignment_start = parser.cursor; int named_slot = 0; double ignored;
|
||||
result = parse_parameter_reference(&parser, &ignored, &named_slot); if (result != SIM_INTERP_OK) { set_error(interpreter, meta, result, (uint32_t)(assignment_start - block + 1)); return result; }
|
||||
skip_space(&parser); if (parser.cursor >= end || *parser.cursor != '=') { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, (uint32_t)(assignment_start - block + 1)); return SIM_INTERP_ERR_PARAMETER; }
|
||||
++parser.cursor; result = parse_expression(&parser, &value); if (result != SIM_INTERP_OK || !isfinite(value)) { if (result == SIM_INTERP_OK) result = SIM_INTERP_ERR_NONFINITE; set_error(interpreter, meta, result, (uint32_t)(assignment_start - block + 1)); return result; }
|
||||
if (named_slot != 0) {
|
||||
size_t n; int assigned = 0;
|
||||
for (n = 0; n < NAMED_PARAMETER_CAPACITY; ++n) if (parser.meta->named[n].used && named_hash(parser.meta->named[n].name) == (uint32_t)named_slot) { parser.meta->named[n].value = value; assigned = 1; break; }
|
||||
if (!assigned) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, (uint32_t)(assignment_start - block + 1)); return SIM_INTERP_ERR_PARAMETER; }
|
||||
} else {
|
||||
const char *ref = assignment_start + 1; unsigned long parameter_index = 0;
|
||||
while (ref < end && isdigit((unsigned char)*ref)) { parameter_index = parameter_index * 10UL + (unsigned long)(*ref - '0'); ++ref; }
|
||||
if (parameter_index < SIM_INTERPRETER_PARAMETER_MIN || parameter_index > SIM_INTERPRETER_PARAMETER_MAX || parser.pending_count >= PENDING_ASSIGNMENTS) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, (uint32_t)(assignment_start - block + 1)); return SIM_INTERP_ERR_PARAMETER; }
|
||||
parser.pending_index[parser.pending_count] = (int)parameter_index; parser.pending_value[parser.pending_count++] = value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
column = (uint32_t)(parser.cursor - block + 1); letter = (char)toupper((unsigned char)*parser.cursor++);
|
||||
if (letter < 'A' || letter > 'Z') { set_error(interpreter, meta, SIM_INTERP_ERR_SYNTAX, column); return SIM_INTERP_ERR_SYNTAX; }
|
||||
result = parse_expression(&parser, &value); if (result != SIM_INTERP_OK) { set_error(interpreter, meta, result, column); return result; }
|
||||
switch (letter) {
|
||||
case 'G': result = apply_g(&next, value, groups); break;
|
||||
case 'M': result = apply_m(&next, value, groups); break;
|
||||
case 'G': result = apply_g(&next, meta, value, groups); break;
|
||||
case 'M': result = apply_m(&next, meta, value, groups); break;
|
||||
case 'N': if (seen_line++) result = SIM_INTERP_ERR_STATE; else if (value < 0.0 || value > 4294967295.0 || floor(value) != value) result = SIM_INTERP_ERR_RANGE; else next.line = (uint32_t)value; break;
|
||||
case 'F': if (seen_feed++) result = SIM_INTERP_ERR_STATE; else if (value < 0.0) result = SIM_INTERP_ERR_RANGE; else feed_value = value; break;
|
||||
case 'S': if (seen_speed++) result = SIM_INTERP_ERR_STATE; else if (value < 0.0) result = SIM_INTERP_ERR_RANGE; else speed_value = value; break;
|
||||
case 'I': case 'J': case 'K': case 'L': case 'Q': case 'D': case 'E': break;
|
||||
case 'P': if (seen_p++) result = SIM_INTERP_ERR_STATE; else p_value = value; break;
|
||||
case 'R': if (seen_r++) result = SIM_INTERP_ERR_STATE; else r_value = value; break;
|
||||
case 'T': if (value < 0.0 || value > 1001.0 || floor(value) != value) result = SIM_INTERP_ERR_RANGE; else meta->selected_tool = (int)value; break;
|
||||
case 'H': if (!isfinite(value)) result = SIM_INTERP_ERR_NONFINITE; else meta->tool_length = value; break;
|
||||
default:
|
||||
index = axis_index(letter);
|
||||
if (index < 0) result = SIM_INTERP_ERR_UNKNOWN_CODE;
|
||||
else if (seen_axis[index]++) result = SIM_INTERP_ERR_STATE;
|
||||
else if (!isfinite(value)) result = SIM_INTERP_ERR_NONFINITE;
|
||||
if (result == SIM_INTERP_OK) axis_values[index] = value;
|
||||
index = axis_index(letter); if (index < 0) result = SIM_INTERP_ERR_UNKNOWN_CODE; else if (seen_axis[index]++) result = SIM_INTERP_ERR_STATE; else if (!isfinite(value)) result = SIM_INTERP_ERR_NONFINITE; if (result == SIM_INTERP_OK) axis_values[index] = value;
|
||||
break;
|
||||
}
|
||||
if (result != SIM_INTERP_OK) return result;
|
||||
if (letter == 'G' && code_is(value, 10)) seen_g10 = 1;
|
||||
if (result != SIM_INTERP_OK) { set_error(interpreter, meta, result, column); return result; }
|
||||
}
|
||||
/* Modal words apply to the whole block, independent of their textual order. */
|
||||
if (seen_feed) next.feed = feed_value * (next.units == SIM_INTERP_UNITS_INCH ? 25.4 : 1.0);
|
||||
if (seen_speed) next.speed = speed_value;
|
||||
skip_space(&parser); if (parser.cursor < end && *parser.cursor != ';') { set_error(interpreter, meta, SIM_INTERP_ERR_SYNTAX, (uint32_t)(parser.cursor - block + 1)); return SIM_INTERP_ERR_SYNTAX; }
|
||||
if (seen_feed) next.feed = feed_value * (next.units == SIM_INTERP_UNITS_INCH ? 25.4 : 1.0); if (seen_speed) next.speed = speed_value;
|
||||
{
|
||||
size_t axis;
|
||||
for (axis = 0; axis < 9; ++axis) if (seen_axis[axis]) {
|
||||
double value = axis_values[axis];
|
||||
double *destination = axis_pointer(&next, (int)axis);
|
||||
if (next.units == SIM_INTERP_UNITS_INCH && axis < 3) value *= 25.4;
|
||||
if (next.distance_mode == SIM_INTERP_INCREMENTAL) *destination += value;
|
||||
else *destination = value;
|
||||
double axis_value = axis_values[axis]; double *destination = axis_pointer(&next, (int)axis);
|
||||
if (next.units == SIM_INTERP_UNITS_INCH && axis < 3) axis_value *= 25.4;
|
||||
if (seen_g10) {
|
||||
if (!seen_p || p_value < 1.0 || p_value > 9.0 || floor(p_value) != p_value) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, 1); return SIM_INTERP_ERR_PARAMETER; }
|
||||
meta->coordinate_offsets[(int)p_value - 1][axis] = axis_value;
|
||||
} else if (next.distance_mode == SIM_INTERP_INCREMENTAL) *destination += axis_value;
|
||||
else *destination = axis_value + meta->coordinate_offsets[meta->coordinate_system > 0 ? meta->coordinate_system - 1 : 0][axis];
|
||||
}
|
||||
}
|
||||
if (!finite_state(&next)) return SIM_INTERP_ERR_NONFINITE;
|
||||
next.line = interpreter->state.line + 1;
|
||||
next.status = SIM_INTERP_OK;
|
||||
interpreter->state = next;
|
||||
interpreter->block_hash = fnv1a64((const unsigned char *)block, length);
|
||||
result = make_canonical(interpreter);
|
||||
if (result != SIM_INTERP_OK) { interpreter->state.status = result; return result; }
|
||||
if (seen_g10 && !seen_axis[0] && !seen_axis[1] && !seen_axis[2]) { set_error(interpreter, meta, SIM_INTERP_ERR_PARAMETER, 1); return SIM_INTERP_ERR_PARAMETER; }
|
||||
if (meta->cycle_mode >= 81 && meta->cycle_mode <= 89 && seen_r && seen_axis[2]) {
|
||||
double return_plane = r_value;
|
||||
if (next.units == SIM_INTERP_UNITS_INCH) return_plane *= 25.4;
|
||||
next.z = return_plane + meta->coordinate_offsets[meta->coordinate_system > 0 ? meta->coordinate_system - 1 : 0][2];
|
||||
}
|
||||
if (meta->tool_length != 0.0 && meta->cutter_comp == 43 && seen_axis[2]) next.z -= meta->tool_length;
|
||||
if (!finite_state(&next)) { set_error(interpreter, meta, SIM_INTERP_ERR_NONFINITE, 1); return SIM_INTERP_ERR_NONFINITE; }
|
||||
if (!seen_line) next.line = interpreter->state.line + 1u; next.status = SIM_INTERP_OK; interpreter->state = next;
|
||||
{
|
||||
size_t item; for (item = 0; item < parser.pending_count; ++item) meta->parameters[parser.pending_index[item]] = parser.pending_value[item];
|
||||
}
|
||||
interpreter->block_hash = fnv1a64((const unsigned char *)block, length); meta->error_column = 0; meta->error_code = SIM_INTERP_OK;
|
||||
result = make_canonical(interpreter); if (result != SIM_INTERP_OK) { set_error(interpreter, meta, result, 1); return result; }
|
||||
return SIM_INTERP_OK;
|
||||
}
|
||||
|
||||
int sim_interpreter_read_state(const sim_interpreter *interpreter, sim_interpreter_state *state) {
|
||||
if (interpreter == 0 || state == 0) return SIM_INTERP_ERR_ARGUMENT;
|
||||
*state = interpreter->state;
|
||||
return SIM_INTERP_OK;
|
||||
}
|
||||
int sim_interpreter_read_state(const sim_interpreter *interpreter, sim_interpreter_state *state) { if (interpreter == NULL || state == NULL) return SIM_INTERP_ERR_ARGUMENT; *state = interpreter->state; return SIM_INTERP_OK; }
|
||||
|
||||
uint32_t sim_interpreter_canonical(const sim_interpreter *interpreter, char *output, uint32_t capacity) {
|
||||
if (interpreter == 0) return 0;
|
||||
if (output == 0 || capacity == 0) return interpreter->canonical_length + 1;
|
||||
if (capacity <= interpreter->canonical_length) return interpreter->canonical_length + 1;
|
||||
memcpy(output, interpreter->canonical, interpreter->canonical_length + 1);
|
||||
return interpreter->canonical_length + 1;
|
||||
if (interpreter == NULL) return 0; if (output == NULL || capacity == 0) return interpreter->canonical_length + 1u; if (capacity <= interpreter->canonical_length) return interpreter->canonical_length + 1u; memcpy(output, interpreter->canonical, interpreter->canonical_length + 1u); return interpreter->canonical_length + 1u;
|
||||
}
|
||||
|
||||
uint64_t sim_interpreter_state_hash(const sim_interpreter *interpreter) {
|
||||
if (interpreter == 0) return 0;
|
||||
return state_hash(&interpreter->state);
|
||||
uint64_t sim_interpreter_state_hash(const sim_interpreter *interpreter) { return interpreter == NULL ? 0 : state_hash(interpreter); }
|
||||
uint64_t sim_interpreter_block_hash(const sim_interpreter *interpreter) { return interpreter == NULL ? 0 : interpreter->block_hash; }
|
||||
uint64_t sim_interpreter_modal_hash(const sim_interpreter *interpreter) { return interpreter == NULL ? 0 : modal_hash(interpreter); }
|
||||
uint32_t sim_interpreter_error_column(const sim_interpreter *interpreter) { interpreter_meta *meta = meta_for(interpreter, 0); return meta == NULL ? 0 : meta->error_column; }
|
||||
int32_t sim_interpreter_error_code(const sim_interpreter *interpreter) { interpreter_meta *meta = meta_for(interpreter, 0); return meta == NULL ? SIM_INTERP_ERR_ARGUMENT : meta->error_code; }
|
||||
|
||||
int sim_interpreter_parameter_set(sim_interpreter *interpreter, uint32_t index, double value) {
|
||||
interpreter_meta *meta = meta_for(interpreter, 1); if (meta == NULL || index < SIM_INTERPRETER_PARAMETER_MIN || index > SIM_INTERPRETER_PARAMETER_MAX) return SIM_INTERP_ERR_PARAMETER; if (!isfinite(value)) return SIM_INTERP_ERR_NONFINITE; meta->parameters[index] = value; return SIM_INTERP_OK;
|
||||
}
|
||||
|
||||
uint64_t sim_interpreter_block_hash(const sim_interpreter *interpreter) {
|
||||
return interpreter == 0 ? 0 : interpreter->block_hash;
|
||||
int sim_interpreter_parameter_get(const sim_interpreter *interpreter, uint32_t index, double *value) {
|
||||
interpreter_meta *meta = meta_for(interpreter, 0); if (meta == NULL || value == NULL || index < SIM_INTERPRETER_PARAMETER_MIN || index > SIM_INTERPRETER_PARAMETER_MAX) return SIM_INTERP_ERR_PARAMETER; *value = meta->parameters[index]; return SIM_INTERP_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user