+/*
+ * when two or more decorators follow a register operand,
+ * consecutive decorators are parsed here.
+ * opmask and zeroing decorators can be placed in any order.
+ * e.g. zmm1 {k2}{z} or zmm2 {z}{k3}
+ * decorator(s) are placed at the end of an operand.
+ */
+static bool parse_braces(decoflags_t *decoflags)
+{
+ int i;
+ bool recover = false;
+
+ i = tokval.t_type;
+ do {
+ if (i == TOKEN_OPMASK) {
+ if (*decoflags & OPMASK_MASK) {
+ nasm_error(ERR_NONFATAL, "opmask k%"PRIu64" is already set",
+ *decoflags & OPMASK_MASK);
+ *decoflags &= ~OPMASK_MASK;
+ }
+ *decoflags |= VAL_OPMASK(nasm_regvals[tokval.t_integer]);
+ } else if (i == TOKEN_DECORATOR) {
+ switch (tokval.t_integer) {
+ case BRC_Z:
+ /*
+ * according to AVX512 spec, only zeroing/merging decorator
+ * is supported with opmask
+ */
+ *decoflags |= GEN_Z(0);
+ break;
+ default:
+ nasm_error(ERR_NONFATAL, "{%s} is not an expected decorator",
+ tokval.t_charptr);
+ break;
+ }
+ } else if (i == ',' || i == TOKEN_EOS){
+ break;
+ } else {
+ nasm_error(ERR_NONFATAL, "only a series of valid decorators"
+ " expected");
+ recover = true;
+ break;
+ }
+ i = stdscan(NULL, &tokval);
+ } while(1);
+
+ return recover;
+}
+
+static int parse_mref(operand *op, const expr *e)
+{
+ int b, i, s; /* basereg, indexreg, scale */
+ int64_t o; /* offset */
+
+ b = i = -1;
+ o = s = 0;
+
+ if (e->type && e->type <= EXPR_REG_END) { /* this bit's a register */
+ bool is_gpr = is_class(REG_GPR,nasm_reg_flags[e->type]);
+
+ if (is_gpr && e->value == 1)
+ b = e->type; /* It can be basereg */
+ else /* No, it has to be indexreg */
+ i = e->type, s = e->value;
+ e++;
+ }
+ if (e->type && e->type <= EXPR_REG_END) { /* it's a 2nd register */
+ bool is_gpr = is_class(REG_GPR,nasm_reg_flags[e->type]);
+
+ if (b != -1) /* If the first was the base, ... */
+ i = e->type, s = e->value; /* second has to be indexreg */
+
+ else if (!is_gpr || e->value != 1) {
+ /* If both want to be index */
+ nasm_error(ERR_NONFATAL,
+ "invalid effective address: two index registers");
+ return -1;
+ } else
+ b = e->type;
+ e++;
+ }
+ if (e->type != 0) { /* is there an offset? */
+ if (e->type <= EXPR_REG_END) { /* in fact, is there an error? */
+ nasm_error(ERR_NONFATAL,
+ "beroset-p-603-invalid effective address");
+ return -1;
+ } else {
+ if (e->type == EXPR_UNKNOWN) {
+ op->opflags |= OPFLAG_UNKNOWN;
+ o = 0; /* doesn't matter what */
+ op->wrt = NO_SEG; /* nor this */
+ op->segment = NO_SEG; /* or this */
+ while (e->type)
+ e++; /* go to the end of the line */
+ } else {
+ if (e->type == EXPR_SIMPLE) {
+ o = e->value;
+ e++;
+ }
+ if (e->type == EXPR_WRT) {
+ op->wrt = e->value;
+ e++;
+ } else
+ op->wrt = NO_SEG;
+ /*
+ * Look for a segment base type.
+ */
+ if (e->type && e->type < EXPR_SEGBASE) {
+ nasm_error(ERR_NONFATAL,
+ "beroset-p-630-invalid effective address");
+ return -1;
+ }
+ while (e->type && e->value == 0)
+ e++;
+ if (e->type && e->value != 1) {
+ nasm_error(ERR_NONFATAL,
+ "beroset-p-637-invalid effective address");
+ return -1;
+ }
+ if (e->type) {
+ op->segment = e->type - EXPR_SEGBASE;
+ e++;
+ } else
+ op->segment = NO_SEG;
+ while (e->type && e->value == 0)
+ e++;
+ if (e->type) {
+ nasm_error(ERR_NONFATAL,
+ "beroset-p-650-invalid effective address");
+ return -1;
+ }
+ }
+ }
+ } else {
+ o = 0;
+ op->wrt = NO_SEG;
+ op->segment = NO_SEG;
+ }
+
+ if (e->type != 0) { /* there'd better be nothing left! */
+ nasm_error(ERR_NONFATAL,
+ "beroset-p-663-invalid effective address");
+ return -1;
+ }
+
+ op->basereg = b;
+ op->indexreg = i;
+ op->scale = s;
+ op->offset = o;
+ return 0;
+}
+
+static void mref_set_optype(operand *op)
+{
+ int b = op->basereg;
+ int i = op->indexreg;
+ int s = op->scale;
+
+ /* It is memory, but it can match any r/m operand */
+ op->type |= MEMORY_ANY;
+
+ if (b == -1 && (i == -1 || s == 0)) {
+ int is_rel = globalbits == 64 &&
+ !(op->eaflags & EAF_ABS) &&
+ ((globalrel &&
+ !(op->eaflags & EAF_FSGS)) ||
+ (op->eaflags & EAF_REL));
+
+ op->type |= is_rel ? IP_REL : MEM_OFFS;
+ }
+
+ if (i != -1) {
+ opflags_t iclass = nasm_reg_flags[i];
+
+ if (is_class(XMMREG,iclass))
+ op->type |= XMEM;
+ else if (is_class(YMMREG,iclass))
+ op->type |= YMEM;
+ else if (is_class(ZMMREG,iclass))
+ op->type |= ZMEM;
+ }
+}
+