/* Copyright Per Bothner 1987. Read the file Q-INFO */
#ifndef QCOMPILE_H
#define QCOMPILE_H
#include <types.h>
#include <stdio.h>
#include <iostream.h>
#include <parsefile.h>
#include <machines.h>

#define IsOffsetLabel(label) ((label)->kind >= SegOffsetToken(0))
#define SetOffsetLabel(label, segment) ((label)->kind=SegOffsetToken(segment))
typedef struct Label /* NOTE: this is compatible with DataToken */
  {
    char kind;		/* unless flags&OffsetLabel, one of the below */
#define StringLabel ConstToken
#define GeneratedLabel GenLabelToken /* (int)name is label number, from generate_label_number() */
    char flags;		/* for usage, see below */
    Object FILLER;
    char *label;	/* if kind==GeneratedLabel, is int instead */
    long offset;
  } *CHandle;

#define DirectPut ((struct Label *)NoValue)
/*extern struct Label DirectPut[1]; * no prefix or label, just inlined data */

struct PrevCompiled {
    struct Label lab; /* must be first field */
    Object value;
    struct PrevCompiled *next;
};

#if 0
struct PendingValue {
    struct PendingValue *next;
    struct Any value;
    struct Label lab;
};
#endif

extern char CompileLoadCode[];
extern CPutGen();

/* register numbering */
#define DataReg(i) (i) /* 0..7 == d0..d7 */
#define AddrReg(i) (8+(i)) /* 8..15 == a0..a7 */
/* Q register usage convention described in token.c */
#define StPtrReg(cf) ((cf)->machineDesc->stPtrReg)
#define FrPtrReg(cf) ((cf)->machineDesc->frPtrReg)
#define LeftReg(cf) ((cf)->machineDesc->argReg)
#define RightReg(cf) ((cf)->machineDesc->ctxReg)
#define AuxReg(cf) ((cf)->machineDesc->auxReg)
#define ArgReg(cf) LeftReg(cf)
#define CtxReg(cf) RightReg(cf)
#define HighestReg AddrReg(7)

#define NumSegments 2
#define NullSegment (-1)
#define TextSegment 0 /* == RTEXT */
#define DataSegment 1 /* == RDATA */
struct SegDesc
  {
    char *switchCommand;
    char *startLabelSuffix;
  };
extern struct SegDesc SegTable[NumSegments];
#define commentBufferLen 60

struct PrevDumped;

struct CFile {
    FILE *_BAD_asmFile;
    FILE *_BAD_auxFile; /* OBSOLETE! extension Qx */
    struct PrevDumped *pendingDumps;
    struct PrevDumped *pendingSymbols;
    long lastId; // Counter generated temporary labels.
    long generate_label_number() { lastId += 2; return lastId; }
    void generate_label(char str[20]) {
	sprintf(str, "_Id_%d", generate_label_number()); }
    short includes;	/* Include files requested */
    char segment;
    char machineType; /* 'm'==m68k; 'v'==vax */
    long segSize[NumSegments];
    RegSet availRegs; /* set of work regs. Usually: machineDesc->workRegs */
    struct ProcExpr *curProc;
    long relocations[NumSegments];
    struct ExtSymbol *firstSymbol;
    long symbolSize;
    char *moduleName;
/*    struct PendingValue *pendingList;*/
    struct Location sourcePos;
#define InstrBufMAX 16 /* in bytes */
    unsigned char instrBuf[InstrBufMAX];
    short instrBufLen;
    short asmPosInLine;
    struct Block *curBlock;
    struct LocalVar *firstVar;
    struct MachineDesc *machineDesc;
    char errors;
    int frameSize;
    short highestPseudoReg;
    short indentation;
    char commentBuffer[commentBufferLen];
    Module *module;
#ifdef __cplusplus
    CFile(char *name, Module *module, int mode);
    void finish();
    ostream* _aux_stream;
    ostream* _asm_stream;
    ostream& aux_stream() { return *_aux_stream; }
    ostream& asm_stream() { return *_asm_stream; }
    ~CFile();
#endif
#if 0
    short regRefCount[HighestReg];
    struct Relocation *(firstReloc[NumSegments]);
    struct Relocation **(nextReloc[NumSegments]);
    struct DataToken CP_token[1]; /* context pointer token */
    struct DataToken *(regToToken[HighestReg]);
    struct DataToken (regToAlias[HighestReg])[1];
#endif
};

#define EvalCompile(cf) (!cf->moduleName) /* Compile called from Eval */
#define CompileForRTL(cf) ((cf)->machineType <= 'Z')
#define CompileToC(cf) ((cf)->machineType <= 'Z')

/* define Vfont_h 1	* if we've output an include for Vfont.h */
extern short Compiling;

#include <token.h>
/* options to PutEffectiveAddress; may be or'd with char machineType */
#define EffAddrFixOpcode 0x1000
#define EffAddrFixOpcode2nd 0x2000
#define EffAddrAlwaysLiteral 0x4000
#define EffAddrMachineTypeMask 0xFF

#define GenLabToString(buffer, label_num) sprintf(buffer, "L_%d_", label_num);

/* options to GetTempToken - must not conflict with a RegMask */
#define GetDataReg RegRangeAsSet(DataReg(0), DataReg(7))
#define GetAddrReg RegRangeAsSet(AddrReg(0), AddrReg(5))
#define GetMayFail 0x10000 /* silently return NULL on failure */
#define GetMemTemp 0x20000
#if 1
extern struct PrevCompiled *PrevCompiledList;
#else
#define PrevCompiledList cf->prevCompiledList
#endif

#ifdef CPLUS
typedef void (*DumpProc)(PrevDumped *, CFile *);

struct AddrLabel {
    void *_addr; /* Is allowed to be mis-aligned */
    char _label[1]; /* Actually, variable number */
    inline char *name() { return _label; }
#ifdef STRICT_ALIGNMENT
    inline void *addr() {
	union {
	    void *addr;
	    char c[sizeof(void*)];
	} u;
	for (int i = sizeof(void*); --i> = 0; )
	    u.c[i] = ((char*)this)[i];
	return u.addr;
    }
#else
    inline void *addr() { return _addr; }
#endif
};

struct PrevDumped {
    struct PrevDumped *next;
    DumpProc dumpProc;
    AddrLabel lab; /* Variable length, since lab.label is variable length */
    inline void *& addr() { return lab._addr; }
    inline char *name() { return lab.name(); }
};

#define PrevDumpedLabelOffset ((int)((struct PrevDumped*)0)->lab._label)
#endif

extern struct DataToken *MakeLabelToken(struct DataToken *token,
	       char *label,  int offset,int indirect);
extern void DumpPending(CFile& cf);
extern void DumpPointerTo(RootPtr val, CFile *cf);
extern void IndentC(CFile *cf);
extern ostream& operator<<(ostream&, Label&);
extern void DoPendingDumps(CFile *cf);
extern char * GenIdent(CFile *);
extern char * GenString(int i = -1);
extern Symbol* GenName();
extern void DumpPointerTo(RootPtr val, CFile *cf);
extern void CompileError(CFile *cf, char *format, ...);
void InsertAlreadyDumped(struct AddrLabel *label);
extern void PrintTypeAsC(struct Type *type, struct Symbol * var, ostream&);
extern void DumpClass(struct ClassDesc *, struct Label *, CFile *);
#ifdef __cplusplus
extern PrevDumped *NewPendingDump(CFile*, const Root *, DumpProc, const char*);
extern void ProcDescCPut(struct Function *func, CFile *cf, char *name);
extern void FuncDumpPtr(struct Function *fnc, CFile *cf);
#endif
#endif QCOMPILE_H
