+//
+// .cstruct [#offset], symbol[.size], ...
+//
+// Lists of registers may also be mentioned; they just take up space. Good for
+// "documentation" purposes:
+//
+// .cstruct a6, .arg1, .arg2, .arg3...
+//
+// Symbols thus created are ABS and EQUATED. Note that this is for
+// compatibility with VBCC and the Remover's library. Thanks to GroovyBee for
+// the suggestion.
+//
+int d_cstruct(void)
+{
+ uint64_t eval = 0; // Default, if no offset specified, is zero
+ WORD rlist;
+ SYM * symbol;
+ char * symbolName;
+ int env;
+ int i;
+
+ if (rgpu || rdsp)
+ return error("directive forbidden in gpu/dsp mode");
+
+ if (*tok == '#')
+ {
+ tok++;
+
+ if (abs_expr(&eval) != OK)
+ return 0;
+
+ // Eat the comma, if it's there
+ if (*tok == ',')
+ tok++;
+ }
+
+ for(;;)
+ {
+ if (*tok == SYMBOL)
+ {
+ symbolName = string[tok[1]];
+
+ // Set env to either local (dot prefixed) or global scope
+ env = (symbolName[0] == '.' ? curenv : 0);
+ symbol = lookup(symbolName, LABEL, env);
+
+ // If the symbol wasn't found, then define it. Otherwise, throw an
+ // error.
+ if (symbol == NULL)
+ {
+ symbol = NewSymbol(symbolName, LABEL, env);
+ symbol->sattr = 0;
+ }
+ else if (symbol->sattr & DEFINED)
+ return error("multiply-defined label '%s'", symbolName);
+
+ // Put symbol in "order of definition" list
+ AddToSymbolDeclarationList(symbol);
+
+ tok += 2;
+
+ // Adjust label start address if it's a word or a long, as a byte
+ // label might have left us on an odd address.
+ switch ((int)*tok)
+ {
+ case DOTW:
+ case DOTL:
+ eval += eval & 0x01;
+ }
+
+ symbol->sattr |= (ABS | DEFINED | EQUATED);
+ symbol->svalue = eval;
+
+ // Check for dot suffixes and adjust space accordingly (longs and
+ // words on an odd boundary get bumped to the next word aligned
+ // address). If no suffix, then throw an error.
+ switch ((int)*tok)
+ {
+ case DOTL:
+ eval += 4;
+ break;
+ case DOTW:
+ eval += 2;
+ break;
+ case DOTB:
+ eval += 1;
+ break;
+ default:
+ return error("Symbol missing dot suffix in .cstruct construct");
+ }
+
+ tok++;
+ }
+ else if (*tok >= REG68_D0 && *tok <= REG68_A7)
+ {
+ if (reglist(&rlist) < 0)
+ return 0;
+
+ for(i=0; i<16; i++, rlist>>=1)
+ {
+ if (rlist & 1)
+ eval += 4;
+ }
+ }
+ else
+ {
+ switch ((int)*tok)
+ {
+ case REG68_USP:
+ case REG68_SSP:
+ case REG68_PC:
+ eval += 2;
+ // FALLTHROUGH
+ case REG68_SR:
+ case REG68_CCR:
+ eval += 2;
+ tok++;
+ break;
+ case EOL:
+ return 0;
+ default:
+ return error(".cstruct syntax");
+ }
+ }
+
+ // Eat commas in between each argument, if they exist
+ if (*tok == ',')
+ tok++;
+ }
+}
+
+
+//
+// Define start of OP object list (allows the use of ORG)
+//
+int d_objproc(void)
+{
+ if ((cursect != TEXT) && (cursect != DATA))
+ {
+ error(".objproc can only be used in the TEXT or DATA segments");
+ return ERROR;
+ }
+
+ // If previous section was DSP or 68000 then we need to reset ORG'd
+ // Addresses
+ if (!robjproc)
+ {
+ orgactive = 0;
+ orgwarning = 0;
+ }
+
+ robjproc = 1; // Set OP assembly
+ rgpu = 0; // Unset GPU assembly
+ rdsp = 0; // Unset DSP assembly
+ dsp56001 = 0; // Unset 56001 assembly
+ //used_architectures |= MOP; // TODO: Should OP have its own dedicated section in the long run?
+ return OK;
+}
+
+