/*
 * ACME - a crossassembler for producing 6502/65c02/65816 code.
 * Copyright (C) 1998 Marco Baye
 * Have a look at "acme.c" for further info
 */

/*
 * Flow control stuff (macro calls, loops, etc.)
 */

#ifndef macro_H
#define macro_H

#include "config.h"
#include "item.h"

/*
 * Macros, conditional assembly, loops and sourcefile-includes are all based on
 * parsing blocks of code. When defining macros or using loops or conditional
 * assembly, the block starts with "{" and ends with "}". In the case of
 * "!source", the given file is treated like a block - the outermost assembler
 * routine uses the same technique to parse the top level file.
 */

/* Format of memory block in case of loop:
 *
 * <Handle of WHILE or UNTIL>
 * <Condition>
 * <Separator>
 * <Assembler lines>
 * <Separator>
 * <Handle of WHILE or UNTIL>
 * <Condition>
 * <Separator>
 */

/* Format of memory block in case of macro:
 *
 * Head:
 *   <Line number of macro definition>
 * Sequential data:
 *   <Name of file macro was defined in>
 *   <Terminator>
 *   <Parameters>
 *   <Separator>
 *   <Assembler lines>
 *   <Separator>
 */
typedef struct MacroStruct MacroStruct;
struct MacroStruct {
  int  nLinesDef;
  char Chars[MAXBLOCKSIZE];
};

static MacroStruct MacroBuffer;
static char       *pFlowBuffer = &MacroBuffer.Chars[0];

/* Temporary storage during macro call */
static ListItem *MacroParameter[MAXMACROPARAMETERS];/* Item pointers */
static Value     MacroParaValue[MAXMACROPARAMETERS];/* Parameter value */
static Value     MacroParaFlags[MAXMACROPARAMETERS];/* Parameter value flags */

/* Separation character within memory block - linefeed never gets through
 * "GetByte()" and is therefore appropriate here */
#define SEPARATOR       10

/* Handle to use for the "else" keyword - rather stupid as there is nothing it
 * could be confused with */
#define ID_ELSE 0

/* Handles to store instead of the UNTIL and WHILE keywords */
enum {
  ID_UNTIL = 'm',/* These characters should not have any meaning */
  ID_WHILE = 'b' /* to any of FN_GetByte()'s filtering rules */
};

/* Current context
 * These are not necessarily current data (top- or sub-filename); during macro
 * processing these vectors points to the data of the file the macro was
 * defined in. Needed for meaningful error messages ! */
typedef struct context context;
struct context {
  int      hByteSource;/* current source handle    */
  int      nLines     ;/* line number inside file  */
  union {
    FILE  *hFile;/* File handle */
    char  *pRAM ;/* Read pointer in block */
  } u;
  char    *pSourceFile ;/* file name                */
  char    *pSourceTitle;/* title of zone or macro   */
  char    *pSourceType ;/* "zone" or "macro"        */
  Sixteen  nZone_Now   ;/* zone                     */
  char     OldFileByte ;/* latest byte from file    */
  char     OldRawByte  ;/* latest byte converted    */
};

/*
 * Prototypes
 */

/* Block end reason and its possible contents */
static int     EndReason;
enum {
  RNONE      ,/* Default value - means "not at end" */
  RENDOFFILE ,/* Reached end of file - either real or by "!end" */
  RENDOFBLOCK,/* Reached separator in RAM block */
  RRIGHTBRACE /* Reached "}" */
};
static context Context[MAXCONTEXTS];
static char    pTitle [MAXCONTEXTS][LSMAX + 1];
static void    FN_FlowPO_offset(void);
static void    FN_FlowPO_zone(void);
static void    FN_FlowPO_subzone(void);
static void    FN_FlowPO_end(void);
static void    FN_FlowPO_source(void);
static void    FN_FlowPO_if(void);
static void    FN_FlowPO_do(void);
static char   *FN_Flow_StoreCondition(char *);
static void    FN_FlowPO_macro(void);
static void    FN_Flow_MacroCall(void);
static void    FN_Flow_NewContext(void);
static char   *FN_Flow_StoreBlock(char *);

#endif
