
#ifndef SYMBOLS__H
#define SYMBOLS__H

/* max symbol_len can be adjusted between SYMMAX_DEFAULT and SYMMAX_MAX*/
#define SYMMAX_DEFAULT 6               /* I will honor this many character symbols */

#define SYMMAX_MAX 64


/* Program sections: */
typedef struct section {
    char           *label;      /* Section name */
    unsigned        type;       /* Section type */
#define SECTION_USER 1          /* user-defined */
#define SECTION_SYSTEM 2        /* A system symbol (like "."; value is an enum) */
#define SECTION_INSTRUCTION 3   /* An instruction code (like "MOV"; value is an enum) */
#define SECTION_PSEUDO 4        /* A pseudo-op (.PSECT, .TITLE, .MACRO, .IF; value is an enum) */
#define SECTION_REGISTER 5      /* Symbol is a register (value 0=$0, value 1=$1, ... $7) */
#define SECTION_USERMACRO 6     /* Symbol is a user macro */

    unsigned        flags;      /* Flags, defined in object.h */
    unsigned        pc;         /* Current offset in the section */
    unsigned        size;       /* Current section size */
    unsigned        sector;     /* Used for complex relocation, and naught else */
} SECTION;

#define SYM_IS_IMPORTED(sym) ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL)

/* Symbol table entries */

typedef struct symbol {
    char           *label;      /* Symbol name */
    unsigned        value;      /* Symbol value */
    int             stmtno;     /* Statement number of symbol's definition */
    unsigned        flags;      /* Symbol flags */
#define SYMBOLFLAG_PERMANENT 1  /* Symbol may not be redefined */
#define SYMBOLFLAG_GLOBAL 2     /* Symbol is global */
#define SYMBOLFLAG_WEAK 4       /* Symbol definition is weak */
#define SYMBOLFLAG_DEFINITION 8 /* Symbol is a global definition, not reference */
#define SYMBOLFLAG_UNDEFINED 16 /* Symbol is a phony, undefined */
#define SYMBOLFLAG_LOCAL 32     /* Set if this is a local label (i.e. 10$) */
#define SYMBOLFLAG_IMPLICIT_GLOBAL 64  /* If migrated from implicit global table to
                                 * normal symbol table */

    SECTION        *section;    /* Section in which this symbol is defined */
    struct symbol  *next;       /* Next symbol with the same hash value */
} SYMBOL;




enum pseudo_ops { P_ASCII,
    P_ASCIZ,
    P_ASECT,
    P_BLKB,
    P_BLKW,
    P_BYTE,
    P_CSECT,
    P_CROSS,
    P_DSABL,
    P_ENABL,
    P_END,
    P_ENDC,
    P_ENDM,
    P_ENDR,
    P_EOT,
    P_ERROR,
    P_EVEN,
    P_FLT2,
    P_FLT4,
    P_GLOBL,
    P_IDENT,
    P_IF,
    P_IFF,
    P_IFT,
    P_IFTF,
    P_IIF,
    P_IRP,
    P_IRPC,
    P_LIBRARY,
    P_LIMIT,
    P_LIST,
    P_MCALL,
    P_MDELETE,
    P_MEXIT,
    P_NARG,
    P_NCHR,
    P_NLIST,
    P_NOCROSS,
    P_NTYPE,
    P_ODD,
    P_PACKED,
    P_PAGE,
    P_PRINT,
    P_PSECT,
    P_RADIX,
    P_RAD50,
    P_REM,
    P_REPT,
    P_RESTORE,
    P_SAVE,
    P_SBTTL,
    P_TITLE,
    P_WORD,
    P_MACRO,
    P_INCLUDE,
    P_WEAK,
    P_IFDF
};

enum instruction_ops {
    I_ADC = 0005500,
    I_ADCB = 0105500,
    I_ADD = 0060000,
    I_ASH = 0072000,
    I_ASHC = 0073000,
    I_ASL = 0006300,
    I_ASLB = 0106300,
    I_ASR = 0006200,
    I_ASRB = 0106200,
    I_BCC = 0103000,
    I_BCS = 0103400,
    I_BEQ = 0001400,
    I_BGE = 0002000,
    I_BGT = 0003000,
    I_BHI = 0101000,
    I_BHIS = 0103000,
    I_BIC = 0040000,
    I_BICB = 0140000,
    I_BIS = 0050000,
    I_BISB = 0150000,
    I_BIT = 0030000,
    I_BITB = 0130000,
    I_BLE = 0003400,
    I_BLO = 0103400,
    I_BLOS = 0101400,
    I_BLT = 0002400,
    I_BMI = 0100400,
    I_BNE = 0001000,
    I_BPL = 0100000,
    I_BPT = 0000003,
    I_BR = 0000400,
    I_BVC = 0102000,
    I_BVS = 0102400,
    I_CALL = 0004700,
    I_CALLR = 0000100,
    I_CCC = 0000257,
    I_CLC = 0000241,
    I_CLN = 0000250,
    I_CLR = 0005000,
    I_CLRB = 0105000,
    I_CLV = 0000242,
    I_CLZ = 0000244,
    I_CMP = 0020000,
    I_CMPB = 0120000,
    I_COM = 0005100,
    I_COMB = 0105100,
    I_DEC = 0005300,
    I_DECB = 0105300,
    I_DIV = 0071000,
    I_EMT = 0104000,
    I_FADD = 0075000,           /* FIS */
    I_FDIV = 0075030,           /* FIS */
    I_FMUL = 0075020,           /* FIS */
    I_FSUB = 0075010,           /* FIS */
    I_HALT = 0000000,
    I_INC = 0005200,
    I_INCB = 0105200,
    I_IOT = 0000004,
    I_JMP = 0000100,
    I_JSR = 0004000,
    I_MARK = 0006400,
    I_MED6X = 0076600,
    I_MED74C = 0076601,
    I_MFPD = 0106500,
    I_MFPI = 0006500,
    I_MFPS = 0106700,
    I_MOV = 0010000,
    I_MOVB = 0110000,
    I_MTPD = 0106600,
    I_MTPI = 0006600,
    I_MTPS = 0106400,
    I_MUL = 0070000,
    I_NEG = 0005400,
    I_NEGB = 0105400,
    I_NOP = 0000240,
    I_RESET = 0000005,
    I_RETURN = 0000207,
    I_ROL = 0006100,
    I_ROLB = 0106100,
    I_ROR = 0006000,
    I_RORB = 0106000,
    I_RTI = 0000002,
    I_RTS = 0000200,
    I_RTT = 0000006,
    I_SBC = 0005600,
    I_SBCB = 0105600,
    I_SCC = 0000277,
    I_SEC = 0000261,
    I_SEN = 0000270,
    I_SEV = 0000262,
    I_SEZ = 0000264,
    I_SOB = 0077000,
    I_SPL = 0000230,
    I_SUB = 0160000,
    I_SWAB = 0000300,
    I_SXT = 0006700,
    I_TRAP = 0104400,
    I_TST = 0005700,
    I_TSTB = 0105700,
    I_WAIT = 0000001,
    I_XFC = 0076700,
    I_XOR = 0074000,
    I_MFPT = 0000007,
    I_CSM = 0007000,
    I_TSTSET = 0007200,
    I_WRTLCK = 0007300,
    /* CIS - Commercial Instruction Set */
    I_CIS_I = 0000100,          /* Inline arguments */
    I_CIS_P = 0000020,          /* Packed instead of Numeric */
    I_ADDN =  0076050,
    I_ADDP =  0076070,
    I_ASHN =  0076056,
    I_ASHP =  0076076,
    I_CMPC =  0076044,
    I_CMPN =  0076052,
    I_CMPP =  0076072,
    I_CVTLN = 0076057,
    I_CVTLP = 0076077,
    I_CVTNL = 0076053,
    I_CVTPL = 0076073,
    I_CVTNP = 0076055,
    I_CVTPN = 0076054,
    I_DIVP =  0076075,
    I_LOCC =  0076040,
    I_L2Dr =  0076020,
    I_L3Dr =  0076060,
    I_MATC =  0076045,
    I_MOVC =  0076030,
    I_MOVRC=  0076031,
    I_MOVTC=  0076032,
    I_MULP =  0076074,
    I_SCANC=  0076042,
    I_SKPC =  0076041,
    I_SPANC=  0076043,
    I_SUBN =  0076051,
    I_SUBP =  0076071,
    /* FPU */
    I_ABSD = 0170600,
    I_ABSF = 0170600,
    I_ADDD = 0172000,
    I_ADDF = 0172000,
    I_CFCC = 0170000,
    I_CLRD = 0170400,
    I_CLRF = 0170400,
    I_CMPD = 0173400,
    I_CMPF = 0173400,
    I_DIVD = 0174400,
    I_DIVF = 0174400,
    I_LDCDF = 0177400,
    I_LDCFD = 0177400,
    I_LDCID = 0177000,
    I_LDCIF = 0177000,
    I_LDCLD = 0177000,
    I_LDCLF = 0177000,
    I_LDD = 0172400,
    I_LDEXP = 0176400,
    I_LDF = 0172400,
    I_LDFPS = 0170100,
    I_MODD = 0171400,
    I_MODF = 0171400,
    I_MULD = 0171000,
    I_MULF = 0171000,
    I_NEGD = 0170700,
    I_NEGF = 0170700,
    I_SETD = 0170011,
    I_SETF = 0170001,
    I_SETI = 0170002,
    I_SETL = 0170012,
    I_STA0 = 0170005,
    I_STB0 = 0170006,
    I_STCDF = 0176000,
    I_STCDI = 0175400,
    I_STCDL = 0175400,
    I_STCFD = 0176000,
    I_STCFI = 0175400,
    I_STCFL = 0175400,
    I_STD = 0174000,
    I_STEXP = 0175000,
    I_STF = 0174000,
    I_STFPS = 0170200,
    I_STST = 0170300,
    I_SUBD = 0173000,
    I_SUBF = 0173000,
    I_TSTD = 0170500,
    I_TSTF = 0170500
};

enum operand_codes { OC_MASK = 0xff00,
    /* mask over flags for operand types */
    OC_NONE = 0x0000,
    /* No operands */
    OC_1GEN = 0x0100,
    /* One general operand (CLR, TST, etc.) */
    OC_2GEN = 0x0200,
    /* Two general operand (MOV, CMP, etc.) */
    OC_BR = 0x0300,
    /* Branch */
    OC_ASH = 0x0400,
    /* ASH and ASHC (one gen, one reg) */
    OC_MARK = 0x0500,
    /* MARK instruction operand */
    OC_JSR = 0x0600,
    /* JSR, XOR (one reg, one gen) */
    OC_1REG = 0x0700,
    /* FADD, FSUB, FMUL, FDIV, RTS */
    OC_SOB = 0x0800,
    /* SOB */
    OC_FPP_FSRCAC = 0x0900,
    /* FPP (fsrc gen, floating ac 0-3) */
    OC_FPP_SRCAC = 0x0a00,
    /* FPP (src gen, floating ac 0-3) */
    OC_FPP_ACFDST = 0x0b00,
    OC_FPP_ACDST = OC_FPP_ACFDST,
    /* FPP (floating ac 0-3, fdst gen) */
    /* OC_FPP_FSRC = 0x0c00, */
    /* FPP fp source: immediate or fsrc gen */
    OC_FPP_FDST = OC_1GEN,
    /* FPP fdst general destination */
    OC_CIS2 = 0x0d00,
    /* CIS with 2 parameter words */
    OC_CIS3 = 0x0e00,
    /* CIS with 3 parameter words */
    OC_CIS4 = 0x0f00,
    /* CIS with 4 parameter words */
    OC__LAST = 0xff00
};



/* symbol tables */

#define HASH_SIZE 1023

typedef struct symbol_table {
    SYMBOL         *hash[HASH_SIZE];
} SYMBOL_TABLE;


/* SYMBOL_ITER is used for iterating thru a symbol table. */
typedef struct symbol_iter {
    int             subscript;  /* Current hash subscript */
    SYMBOL         *current;    /* Current symbol */
} SYMBOL_ITER;


#ifndef SYMBOLS__C

extern int      symbol_len;     /* max. len of symbols. default = 6 */
extern int      symbol_allow_underscores;       /* allow "_" in symbol names */

extern SYMBOL  *reg_sym[8];     /* Keep the register symbols in a handy array */

extern SYMBOL_TABLE system_st;  /* System symbols (Instructions,
                                   pseudo-ops, registers) */

extern SYMBOL_TABLE section_st; /* Program sections */

extern SYMBOL_TABLE symbol_st;  /* User symbols */

extern SYMBOL_TABLE macro_st;   /* Macros */

extern SYMBOL_TABLE implicit_st;        /* The symbols which may be implicit globals */

extern SYMBOL_TABLE undefined_st;       /* The symbols which may be undefined */

#endif

int             hash_name(
    char *label);

SYMBOL         *add_sym(
    char *label,
    unsigned value,
    unsigned flags,
    SECTION *section,
    SYMBOL_TABLE *table);
SYMBOL         *first_sym(
    SYMBOL_TABLE *table,
    SYMBOL_ITER *iter);

SYMBOL         *lookup_sym(
    char *label,
    SYMBOL_TABLE *table);
SYMBOL         *next_sym(
    SYMBOL_TABLE *table,
    SYMBOL_ITER *iter);
void            free_sym(
    SYMBOL *sym);

void            remove_sym(
    SYMBOL *sym,
    SYMBOL_TABLE *table);

char           *symflags(
    SYMBOL *sym);

void            add_table(
    SYMBOL *sym,
    SYMBOL_TABLE *table);


void            add_symbols(
    SECTION *current_section);

void            list_symbol_table(
    void);
#endif
