parser: simplify code by keeping a pointer to the current operand
authorH. Peter Anvin <hpa@linux.intel.com>
Fri, 27 Sep 2013 00:23:08 +0000 (17:23 -0700)
committerJin Kyu Song <jin.kyu.song@intel.com>
Wed, 20 Nov 2013 19:29:41 +0000 (11:29 -0800)
There is an awful lot of syntax-heavy "result->oprs[operand]" going
on; simplify by making a pointer to the current operand.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com>
parser.c

index 37a5e1c..ba994b4 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -106,7 +106,7 @@ static int prefix_slot(int prefix)
     }
 }
 
-static void process_size_override(insn *result, int operand)
+static void process_size_override(insn *result, operand *op)
 {
     if (tasm_compatible_mode) {
         switch ((int)tokval.t_integer) {
@@ -123,23 +123,23 @@ static void process_size_override(insn *result, int operand)
              * but 32-bit flat model addressing in our code.
              */
         case S_BYTE:
-            result->oprs[operand].type |= BITS8;
+            op->type |= BITS8;
             break;
         case S_WORD:
-            result->oprs[operand].type |= BITS16;
+            op->type |= BITS16;
             break;
         case S_DWORD:
         case S_LONG:
-            result->oprs[operand].type |= BITS32;
+            op->type |= BITS32;
             break;
         case S_QWORD:
-            result->oprs[operand].type |= BITS64;
+            op->type |= BITS64;
             break;
         case S_TWORD:
-            result->oprs[operand].type |= BITS80;
+            op->type |= BITS80;
             break;
         case S_OWORD:
-            result->oprs[operand].type |= BITS128;
+            op->type |= BITS128;
             break;
         default:
             nasm_error(ERR_NONFATAL,
@@ -150,17 +150,17 @@ static void process_size_override(insn *result, int operand)
         /* Standard NASM compatible syntax */
         switch ((int)tokval.t_integer) {
         case S_NOSPLIT:
-            result->oprs[operand].eaflags |= EAF_TIMESTWO;
+            op->eaflags |= EAF_TIMESTWO;
             break;
         case S_REL:
-            result->oprs[operand].eaflags |= EAF_REL;
+            op->eaflags |= EAF_REL;
             break;
         case S_ABS:
-            result->oprs[operand].eaflags |= EAF_ABS;
+            op->eaflags |= EAF_ABS;
             break;
         case S_BYTE:
-            result->oprs[operand].disp_size = 8;
-            result->oprs[operand].eaflags |= EAF_BYTEOFFS;
+            op->disp_size = 8;
+            op->eaflags |= EAF_BYTEOFFS;
             break;
         case P_A16:
         case P_A32:
@@ -173,17 +173,17 @@ static void process_size_override(insn *result, int operand)
                 result->prefixes[PPS_ASIZE] = tokval.t_integer;
             break;
         case S_WORD:
-            result->oprs[operand].disp_size = 16;
-            result->oprs[operand].eaflags |= EAF_WORDOFFS;
+            op->disp_size = 16;
+            op->eaflags |= EAF_WORDOFFS;
             break;
         case S_DWORD:
         case S_LONG:
-            result->oprs[operand].disp_size = 32;
-            result->oprs[operand].eaflags |= EAF_WORDOFFS;
+            op->disp_size = 32;
+            op->eaflags |= EAF_WORDOFFS;
             break;
         case S_QWORD:
-            result->oprs[operand].disp_size = 64;
-            result->oprs[operand].eaflags |= EAF_WORDOFFS;
+            op->disp_size = 64;
+            op->eaflags |= EAF_WORDOFFS;
             break;
         default:
             nasm_error(ERR_NONFATAL, "invalid size specification in"
@@ -246,7 +246,7 @@ insn *parse_line(int pass, char *buffer, insn *result, ldfunc ldef)
 {
     bool insn_is_label = false;
     struct eval_hints hints;
-    int operand;
+    int opnum;
     int critical;
     bool first;
     bool recover;
@@ -266,10 +266,8 @@ restart_parse:
     result->evex_brerop = -1;   /* Reset EVEX broadcasting/ER op position */
 
     /* Ignore blank lines */
-    if (i == TOKEN_EOS) {
-        result->opcode = I_none;
-        return result;
-    }
+    if (i == TOKEN_EOS)
+        goto fail;
 
     if (i != TOKEN_ID       &&
         i != TOKEN_INSN     &&
@@ -277,8 +275,7 @@ restart_parse:
         (i != TOKEN_REG || !IS_SREG(tokval.t_integer))) {
         nasm_error(ERR_NONFATAL,
                    "label or instruction expected at start of line");
-        result->opcode = I_none;
-        return result;
+        goto fail;
     }
 
     if (i == TOKEN_ID || (insn_is_label && i == TOKEN_INSN)) {
@@ -306,10 +303,8 @@ restart_parse:
     }
 
     /* Just a label here */
-    if (i == TOKEN_EOS) {
-        result->opcode = I_none;
-        return result;
-    }
+    if (i == TOKEN_EOS)
+        goto fail;
 
     nasm_build_assert(P_none != 0);
     memset(result->prefixes, P_none, sizeof(result->prefixes));
@@ -328,10 +323,8 @@ restart_parse:
             i = stdscan(NULL, &tokval);
             value = evaluate(stdscan, NULL, &tokval, NULL, pass0, nasm_error, NULL);
             i = tokval.t_type;
-            if (!value) {       /* but, error in evaluator */
-                result->opcode = I_none;    /* unrecoverable parse error: */
-                return result;  /* ignore this instruction */
-            }
+            if (!value)                  /* Error in evaluator */
+                goto fail;
             if (!is_simple(value)) {
                 nasm_error(ERR_NONFATAL,
                       "non-constant argument supplied to TIMES");
@@ -382,8 +375,7 @@ restart_parse:
             return result;
         } else {
             nasm_error(ERR_NONFATAL, "parser: instruction expected");
-            result->opcode = I_none;
-            return result;
+            goto fail;
         }
     }
 
@@ -526,10 +518,8 @@ is_expression:
                 value = evaluate(stdscan, NULL, &tokval, NULL,
                                  critical, nasm_error, NULL);
                 i = tokval.t_type;
-                if (!value) {   /* error in evaluator */
-                    result->opcode = I_none;        /* unrecoverable parse error: */
-                    return result;      /* ignore this instruction */
-                }
+                if (!value)                  /* Error in evaluator */
+                    goto fail;
                 if (is_unknown(value)) {
                     eop->type = EOT_DB_NUMBER;
                     eop->offset = 0;    /* doesn't matter what we put */
@@ -557,8 +547,7 @@ is_expression:
             if (i != ',') {
                 nasm_error(ERR_NONFATAL, "comma expected after operand %d",
                            oper_num);
-                result->opcode = I_none;/* unrecoverable parse error: */
-                return result;          /* ignore this instruction */
+                goto fail;
             }
         }
 
@@ -588,8 +577,7 @@ is_expression:
              * If we reach here, one of the above errors happened.
              * Throw the instruction away.
              */
-            result->opcode = I_none;
-            return result;
+            goto fail;
         } else /* DB ... */ if (oper_num == 0)
             nasm_error(ERR_WARNING | ERR_PASS1,
                   "no operand for data declaration");
@@ -604,17 +592,18 @@ is_expression:
      * of these, separated by commas, and terminated by a zero token.
      */
 
-    for (operand = 0; operand < MAX_OPERANDS; operand++) {
+    for (opnum = 0; opnum < MAX_OPERANDS; opnum++) {
+        operand *op = &result->oprs[opnum];
         expr *value;            /* used most of the time */
         int mref;               /* is this going to be a memory ref? */
         int bracket;            /* is it a [] mref, or a & mref? */
         int setsize = 0;
         decoflags_t brace_flags = 0;    /* flags for decorators in braces */
 
-        result->oprs[operand].disp_size = 0;    /* have to zero this whatever */
-        result->oprs[operand].eaflags   = 0;    /* and this */
-        result->oprs[operand].opflags   = 0;
-        result->oprs[operand].decoflags = 0;
+        op->disp_size = 0;    /* have to zero this whatever */
+        op->eaflags   = 0;    /* and this */
+        op->opflags   = 0;
+        op->decoflags = 0;
 
         i = stdscan(NULL, &tokval);
         if (i == TOKEN_EOS)
@@ -624,64 +613,64 @@ is_expression:
             goto restart_parse;
         }
         first = false;
-        result->oprs[operand].type = 0; /* so far, no override */
+        op->type = 0; /* so far, no override */
         while (i == TOKEN_SPECIAL) {    /* size specifiers */
             switch ((int)tokval.t_integer) {
             case S_BYTE:
                 if (!setsize)   /* we want to use only the first */
-                    result->oprs[operand].type |= BITS8;
+                    op->type |= BITS8;
                 setsize = 1;
                 break;
             case S_WORD:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS16;
+                    op->type |= BITS16;
                 setsize = 1;
                 break;
             case S_DWORD:
             case S_LONG:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS32;
+                    op->type |= BITS32;
                 setsize = 1;
                 break;
             case S_QWORD:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS64;
+                    op->type |= BITS64;
                 setsize = 1;
                 break;
             case S_TWORD:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS80;
+                    op->type |= BITS80;
                 setsize = 1;
                 break;
             case S_OWORD:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS128;
+                    op->type |= BITS128;
                 setsize = 1;
                 break;
             case S_YWORD:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS256;
+                    op->type |= BITS256;
                 setsize = 1;
                 break;
             case S_ZWORD:
                 if (!setsize)
-                    result->oprs[operand].type |= BITS512;
+                    op->type |= BITS512;
                 setsize = 1;
                 break;
             case S_TO:
-                result->oprs[operand].type |= TO;
+                op->type |= TO;
                 break;
             case S_STRICT:
-                result->oprs[operand].type |= STRICT;
+                op->type |= STRICT;
                 break;
             case S_FAR:
-                result->oprs[operand].type |= FAR;
+                op->type |= FAR;
                 break;
             case S_NEAR:
-                result->oprs[operand].type |= NEAR;
+                op->type |= NEAR;
                 break;
             case S_SHORT:
-                result->oprs[operand].type |= SHORT;
+                op->type |= SHORT;
                 break;
             default:
                 nasm_error(ERR_NONFATAL, "invalid operand size specification");
@@ -694,7 +683,7 @@ is_expression:
             bracket = (i == '[');
             i = stdscan(NULL, &tokval); /* then skip the colon */
             while (i == TOKEN_SPECIAL || i == TOKEN_PREFIX) {
-                process_size_override(result, operand);
+                process_size_override(result, op);
                 i = stdscan(NULL, &tokval);
             }
         } else {                /* immediate operand, or register */
@@ -702,22 +691,20 @@ is_expression:
             bracket = false;    /* placate optimisers */
         }
 
-        if ((result->oprs[operand].type & FAR) && !mref &&
+        if ((op->type & FAR) && !mref &&
             result->opcode != I_JMP && result->opcode != I_CALL) {
             nasm_error(ERR_NONFATAL, "invalid use of FAR operand specifier");
         }
 
         value = evaluate(stdscan, NULL, &tokval,
-                         &result->oprs[operand].opflags,
+                         &op->opflags,
                          critical, nasm_error, &hints);
         i = tokval.t_type;
-        if (result->oprs[operand].opflags & OPFLAG_FORWARD) {
+        if (op->opflags & OPFLAG_FORWARD) {
             result->forw_ref = true;
         }
-        if (!value) {           /* nasm_error in evaluator */
-            result->opcode = I_none;        /* unrecoverable parse error: */
-            return result;      /* ignore this instruction */
-        }
+        if (!value)                  /* Error in evaluator */
+            goto fail;
         if (i == ':' && mref) { /* it was seg:offset */
             /*
              * Process the segment override.
@@ -732,26 +719,24 @@ is_expression:
             else {
                 result->prefixes[PPS_SEG] = value->type;
                 if (IS_FSGS(value->type))
-                    result->oprs[operand].eaflags |= EAF_FSGS;
+                    op->eaflags |= EAF_FSGS;
             }
 
             i = stdscan(NULL, &tokval); /* then skip the colon */
             while (i == TOKEN_SPECIAL || i == TOKEN_PREFIX) {
-                process_size_override(result, operand);
+                process_size_override(result, op);
                 i = stdscan(NULL, &tokval);
             }
             value = evaluate(stdscan, NULL, &tokval,
-                             &result->oprs[operand].opflags,
+                             &op->opflags,
                              critical, nasm_error, &hints);
             i = tokval.t_type;
-            if (result->oprs[operand].opflags & OPFLAG_FORWARD) {
+            if (op->opflags & OPFLAG_FORWARD) {
                 result->forw_ref = true;
             }
             /* and get the offset */
-            if (!value) {       /* but, error in evaluator */
-                result->opcode = I_none;    /* unrecoverable parse error: */
-                return result;  /* ignore this instruction */
-            }
+            if (!value)                  /* Error in evaluator */
+                goto fail;
         }
 
         recover = false;
@@ -791,7 +776,7 @@ is_expression:
                                          "line expected after operand");
                 recover = true;
             } else if (i == ':') {
-                result->oprs[operand].type |= COLON;
+                op->type |= COLON;
             } else if (i == TOKEN_DECORATOR || i == TOKEN_OPMASK) {
                 /* parse opmask (and zeroing) after an operand */
                 recover = parse_braces(&brace_flags);
@@ -814,8 +799,8 @@ is_expression:
             int64_t o;          /* offset */
 
             b = i = -1, o = s = 0;
-            result->oprs[operand].hintbase = hints.base;
-            result->oprs[operand].hinttype = hints.type;
+            op->hintbase = hints.base;
+            op->hinttype = hints.type;
 
             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]);
@@ -836,8 +821,7 @@ is_expression:
                     /* If both want to be index */
                     nasm_error(ERR_NONFATAL,
                                "invalid effective address: two index registers");
-                    result->opcode = I_none;
-                    return result;
+                    goto fail;
                 } else
                     b = e->type;
                 e++;
@@ -846,14 +830,13 @@ is_expression:
                 if (e->type <= EXPR_REG_END) {  /* in fact, is there an error? */
                     nasm_error(ERR_NONFATAL,
                           "beroset-p-603-invalid effective address");
-                    result->opcode = I_none;
-                    return result;
+                    goto fail;
                 } else {
                     if (e->type == EXPR_UNKNOWN) {
-                        result->oprs[operand].opflags |= OPFLAG_UNKNOWN;
+                        op->opflags |= OPFLAG_UNKNOWN;
                         o = 0;  /* doesn't matter what */
-                        result->oprs[operand].wrt = NO_SEG;     /* nor this */
-                        result->oprs[operand].segment = NO_SEG; /* or this */
+                        op->wrt = NO_SEG;     /* nor this */
+                        op->segment = NO_SEG; /* or this */
                         while (e->type)
                             e++;        /* go to the end of the line */
                     } else {
@@ -862,118 +845,114 @@ is_expression:
                             e++;
                         }
                         if (e->type == EXPR_WRT) {
-                            result->oprs[operand].wrt = e->value;
+                            op->wrt = e->value;
                             e++;
                         } else
-                            result->oprs[operand].wrt = NO_SEG;
+                            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");
-                            result->opcode = I_none;
-                            return result;
+                            goto fail;
                         }
                         while (e->type && e->value == 0)
                             e++;
                         if (e->type && e->value != 1) {
                             nasm_error(ERR_NONFATAL,
                                   "beroset-p-637-invalid effective address");
-                            result->opcode = I_none;
-                            return result;
+                            goto fail;
                         }
                         if (e->type) {
-                            result->oprs[operand].segment =
+                            op->segment =
                                 e->type - EXPR_SEGBASE;
                             e++;
                         } else
-                            result->oprs[operand].segment = NO_SEG;
+                            op->segment = NO_SEG;
                         while (e->type && e->value == 0)
                             e++;
                         if (e->type) {
                             nasm_error(ERR_NONFATAL,
                                   "beroset-p-650-invalid effective address");
-                            result->opcode = I_none;
-                            return result;
+                            goto fail;
                         }
                     }
                 }
             } else {
                 o = 0;
-                result->oprs[operand].wrt = NO_SEG;
-                result->oprs[operand].segment = NO_SEG;
+                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");
-                result->opcode = I_none;
-                return result;
+                goto fail;
             }
 
             /* It is memory, but it can match any r/m operand */
-            result->oprs[operand].type |= MEMORY_ANY;
+            op->type |= MEMORY_ANY;
 
             if (b == -1 && (i == -1 || s == 0)) {
                 int is_rel = globalbits == 64 &&
-                    !(result->oprs[operand].eaflags & EAF_ABS) &&
+                    !(op->eaflags & EAF_ABS) &&
                     ((globalrel &&
-                      !(result->oprs[operand].eaflags & EAF_FSGS)) ||
-                     (result->oprs[operand].eaflags & EAF_REL));
+                      !(op->eaflags & EAF_FSGS)) ||
+                     (op->eaflags & EAF_REL));
 
-                result->oprs[operand].type |= is_rel ? IP_REL : MEM_OFFS;
+                op->type |= is_rel ? IP_REL : MEM_OFFS;
             }
 
             if (i != -1) {
                 opflags_t iclass = nasm_reg_flags[i];
 
                 if (is_class(XMMREG,iclass))
-                    result->oprs[operand].type |= XMEM;
+                    op->type |= XMEM;
                 else if (is_class(YMMREG,iclass))
-                    result->oprs[operand].type |= YMEM;
+                    op->type |= YMEM;
                 else if (is_class(ZMMREG,iclass))
-                    result->oprs[operand].type |= ZMEM;
+                    op->type |= ZMEM;
             }
 
-            result->oprs[operand].basereg = b;
-            result->oprs[operand].indexreg = i;
-            result->oprs[operand].scale = s;
-            result->oprs[operand].offset = o;
-            result->oprs[operand].decoflags |= brace_flags;
+            op->basereg = b;
+            op->indexreg = i;
+            op->scale = s;
+            op->offset = o;
+            op->decoflags |= brace_flags;
         } else {                /* it's not a memory reference */
             if (is_just_unknown(value)) {       /* it's immediate but unknown */
-                result->oprs[operand].type      |= IMMEDIATE;
-                result->oprs[operand].opflags   |= OPFLAG_UNKNOWN;
-                result->oprs[operand].offset    = 0;        /* don't care */
-                result->oprs[operand].segment   = NO_SEG;   /* don't care again */
-                result->oprs[operand].wrt       = NO_SEG;   /* still don't care */
+                op->type      |= IMMEDIATE;
+                op->opflags   |= OPFLAG_UNKNOWN;
+                op->offset    = 0;        /* don't care */
+                op->segment   = NO_SEG;   /* don't care again */
+                op->wrt       = NO_SEG;   /* still don't care */
 
-                if(optimizing >= 0 && !(result->oprs[operand].type & STRICT)) {
+                if(optimizing >= 0 && !(op->type & STRICT)) {
                     /* Be optimistic */
-                    result->oprs[operand].type |=
+                    op->type |=
                         UNITY | SBYTEWORD | SBYTEDWORD | UDWORD | SDWORD;
                 }
             } else if (is_reloc(value)) {       /* it's immediate */
-                result->oprs[operand].type      |= IMMEDIATE;
-                result->oprs[operand].offset    = reloc_value(value);
-                result->oprs[operand].segment   = reloc_seg(value);
-                result->oprs[operand].wrt       = reloc_wrt(value);
+                op->type      |= IMMEDIATE;
+                op->offset    = reloc_value(value);
+                op->segment   = reloc_seg(value);
+                op->wrt       = reloc_wrt(value);
 
                 if (is_simple(value)) {
                     uint64_t n = reloc_value(value);
                     if (n == 1)
-                        result->oprs[operand].type |= UNITY;
+                        op->type |= UNITY;
                     if (optimizing >= 0 &&
-                        !(result->oprs[operand].type & STRICT)) {
+                        !(op->type & STRICT)) {
                         if ((uint32_t) (n + 128) <= 255)
-                            result->oprs[operand].type |= SBYTEDWORD;
+                            op->type |= SBYTEDWORD;
                         if ((uint16_t) (n + 128) <= 255)
-                            result->oprs[operand].type |= SBYTEWORD;
+                            op->type |= SBYTEWORD;
                         if (n <= 0xFFFFFFFF)
-                            result->oprs[operand].type |= UDWORD;
+                            op->type |= UDWORD;
                         if (n + 0x80000000 <= 0xFFFFFFFF)
-                            result->oprs[operand].type |= SDWORD;
+                            op->type |= SDWORD;
                     }
                 }
             } else if(value->type == EXPR_RDSAE) {
@@ -982,15 +961,14 @@ is_expression:
                  * put the decorator information in the (opflag_t) type field
                  * of previous operand.
                  */
-                operand --;
+                opnum--; op--;
                 switch (value->value) {
                 case BRC_RN:
                 case BRC_RU:
                 case BRC_RD:
                 case BRC_RZ:
                 case BRC_SAE:
-                    result->oprs[operand].decoflags  |=
-                                        (value->value == BRC_SAE ? SAE : ER);
+                    op->decoflags |= (value->value == BRC_SAE ? SAE : ER);
                     result->evex_rm = value->value;
                     break;
                 default:
@@ -1002,8 +980,7 @@ is_expression:
 
                 if (value->type >= EXPR_SIMPLE || value->value != 1) {
                     nasm_error(ERR_NONFATAL, "invalid operand type");
-                    result->opcode = I_none;
-                    return result;
+                    goto fail;
                 }
 
                 /*
@@ -1012,42 +989,41 @@ is_expression:
                 for (i = 1; value[i].type; i++)
                     if (value[i].value) {
                         nasm_error(ERR_NONFATAL, "invalid operand type");
-                        result->opcode = I_none;
-                        return result;
+                        goto fail;
                     }
 
                 /* clear overrides, except TO which applies to FPU regs */
-                if (result->oprs[operand].type & ~TO) {
+                if (op->type & ~TO) {
                     /*
                      * we want to produce a warning iff the specified size
                      * is different from the register size
                      */
-                    rs = result->oprs[operand].type & SIZE_MASK;
+                    rs = op->type & SIZE_MASK;
                 } else
                     rs = 0;
 
-                result->oprs[operand].type      &= TO;
-                result->oprs[operand].type      |= REGISTER;
-                result->oprs[operand].type      |= nasm_reg_flags[value->type];
-                result->oprs[operand].decoflags |= brace_flags;
-                result->oprs[operand].basereg   = value->type;
+                op->type      &= TO;
+                op->type      |= REGISTER;
+                op->type      |= nasm_reg_flags[value->type];
+                op->decoflags |= brace_flags;
+                op->basereg   = value->type;
 
-                if (rs && (result->oprs[operand].type & SIZE_MASK) != rs)
+                if (rs && (op->type & SIZE_MASK) != rs)
                     nasm_error(ERR_WARNING | ERR_PASS1,
                           "register size specification ignored");
             }
         }
 
         /* remember the position of operand having broadcasting/ER mode */
-        if (result->oprs[operand].decoflags & (BRDCAST_MASK | ER | SAE))
-            result->evex_brerop = operand;
+        if (op->decoflags & (BRDCAST_MASK | ER | SAE))
+            result->evex_brerop = opnum;
     }
 
-    result->operands = operand; /* set operand count */
+    result->operands = opnum; /* set operand count */
 
     /* clear remaining operands */
-    while (operand < MAX_OPERANDS)
-        result->oprs[operand++].type = 0;
+    while (opnum < MAX_OPERANDS)
+        result->oprs[opnum++].type = 0;
 
     /*
      * Transform RESW, RESD, RESQ, REST, RESO, RESY, RESZ into RESB.
@@ -1086,6 +1062,10 @@ is_expression:
     }
 
     return result;
+
+fail:
+    result->opcode = I_none;
+    return result;
 }
 
 static int is_comma_next(void)