#ifndef STATEMENT_H
#define STATEMENT_H

/** **********************************************************************
** Module:  Statement \file stmt.h
** Description: This module implements the Statement abstraction.  A
**  statement is, in effect, a typeless Expression.  Due to the
**  existence of complex language constructs, however, it often is
**  not practical to implement the abstraction thus.  For this reason,
**  there is a separate module for statements.  This abstraction
**  supports various looping constructs, if/then/else, switch
**  statements, and procedure calls.
** Constants:
**  STATEMENT_NULL  - the null statement
**
************************************************************************/

/*
 * This software was developed by U.S. Government employees as part of
 * their official duties and is not subject to copyright.
 *
 * $Log: stmt.h,v $
 * Revision 1.3  1997/01/21 19:17:11  dar
 * made C++ compatible
 *
 * Revision 1.2  1993/10/15  18:48:24  libes
 * CADDETC certified
 *
 * Revision 1.5  1993/02/16  03:27:02  libes
 * removed artificial begin/end nesting for improved reconstruction (printing)
 * of original Express file
 *
 * Revision 1.4  1992/08/18  17:12:41  libes
 * rm'd extraneous error messages
 *
 * Revision 1.3  1992/06/08  18:06:24  libes
 * prettied up interface to print_objects_when_running
 */

/*************/
/* constants */
/*************/

#define STATEMENT_NULL      (Statement)0
#define STATEMENT_LIST_NULL (Linked_List)0

/*****************/
/* packages used */
/*****************/

#include <sc_export.h>
#include "expbasic.h"   /* get basic definitions */
#include "scope.h"

/************/
/* typedefs */
/************/

typedef struct Statement_  * Statement,
        *Alias,
        *Assignment,
        *Case_Statement,
        *Compound_Statement,
        *Conditional,
        *Loop,
        *Procedure_Call,
        *Return_Statement;

typedef struct Scope_ * Increment;

/****************/
/* modules used */
/****************/

#include "expr.h"
#include "alg.h"

/***************************/
/* hidden type definitions */
/***************************/

#define STMT_ASSIGN 0x1
#define STMT_CASE   0x2
#define STMT_COMPOUND   0x4
#define STMT_COND   0x8
#define STMT_LOOP   0x10
#define STMT_PCALL  0x20
#define STMT_RETURN 0x40
#define STMT_ALIAS  0x80
#define STMT_SKIP   0x100
#define STMT_ESCAPE 0x200

/* these should probably all be expression types */

struct Statement_ {
    Symbol symbol;  /**< can hold pcall or alias name but otherwise is not used for anything */
    int type;   /**< one of STMT_XXX above */
    /* hey, is there nothing in common beside symbol and private data?? */
    union u_statement {
        struct Alias_     *     alias;
        struct Assignment_   *  assign;
        struct Case_Statement_   *  Case;
        struct Compound_Statement_ * compound;
        struct Conditional_  *  cond;
        struct Loop_      *     loop;
        struct Procedure_Call_   *  proc;
        struct Return_Statement_  * ret;
        /* skip & escape have no data */
    } u;
};

struct Alias_ {
    struct Scope_ * scope;
    struct Variable_ * variable;
    Linked_List statements;     /**< list of statements */
};

struct Assignment_ {
    Expression lhs;
    Expression rhs;
};

struct Case_Statement_ {
    Expression selector;
    Linked_List cases;
};

struct Compound_Statement_ {
    Linked_List statements;
};

struct Conditional_ {
    Expression test;
    Linked_List code;           /**< list of statements */
    Linked_List otherwise;      /**< list of statements */
};

struct Loop_ {
    struct Scope_ * scope;      /**< scope for increment control */
    Expression while_expr;
    Expression until_expr;
    Linked_List statements;     /**< list of statements */
};

/** this is an element in the optional Loop scope */
struct Increment_ {
    Expression init;
    Expression end;
    Expression increment;
};

struct Procedure_Call_ {
    struct Scope_ * procedure;
    Linked_List parameters; /**< list of expressions */
};

struct Return_Statement_ {
    Expression value;
};



/********************/
/* global variables */
/********************/

extern SC_EXPRESS_EXPORT struct freelist_head STMT_fl;

extern SC_EXPRESS_EXPORT struct freelist_head ALIAS_fl;
extern SC_EXPRESS_EXPORT struct freelist_head ASSIGN_fl;
extern SC_EXPRESS_EXPORT struct freelist_head CASE_fl;
extern SC_EXPRESS_EXPORT struct freelist_head COMP_STMT_fl;
extern SC_EXPRESS_EXPORT struct freelist_head COND_fl;
extern SC_EXPRESS_EXPORT struct freelist_head LOOP_fl;
extern SC_EXPRESS_EXPORT struct freelist_head PCALL_fl;
extern SC_EXPRESS_EXPORT struct freelist_head RET_fl;
extern SC_EXPRESS_EXPORT struct freelist_head INCR_fl;

extern SC_EXPRESS_EXPORT Statement STATEMENT_ESCAPE;
extern SC_EXPRESS_EXPORT Statement STATEMENT_SKIP;

/******************************/
/* macro function definitions */
/******************************/

#define STMT_new()  (struct Statement_ *)ALLOC_new(&STMT_fl)
#define STMT_destroy(x) ALLOC_destroy(&STMT_fl,(Freelist *)x)

#define ALIAS_new()     (struct Alias_ *)ALLOC_new(&ALIAS_fl)
#define ALIAS_destroy(x)        ALLOC_destroy(&ALIAS_fl,(Freelist *)x)
#define ASSIGN_new()        (struct Assignment_ *)ALLOC_new(&ASSIGN_fl)
#define ASSIGN_destroy(x)       ALLOC_destroy(&ASSIGN_fl,(Freelist *)x)
#define CASE_new()      (struct Case_Statement_ *)ALLOC_new(&CASE_fl)
#define CASE_destroy(x)     ALLOC_destroy(&CASE_fl,(Freelist *)x)
#define COMP_STMT_new()     (struct Compound_Statement_ *)ALLOC_new(&COMP_STMT_fl)
#define COMP_STMT_destroy(x)        ALLOC_destroy(&COMP_STMT_fl,(Freelist *)x)
#define COND_new()      (struct Conditional_ *)ALLOC_new(&COND_fl)
#define COND_destroy(x)     ALLOC_destroy(&COND_fl,(Freelist *)x)
#define LOOP_new()      (struct Loop_ *)ALLOC_new(&LOOP_fl)
#define LOOP_destroy(x)     ALLOC_destroy(&LOOP_fl,(Freelist *)x)
#define PCALL_new()     (struct Procedure_Call_ *)ALLOC_new(&PCALL_fl)
#define PCALL_destroy(x)    ALLOC_destroy(&PCALL_fl,(Freelist *)x)
#define RET_new()       (struct Return_Statement_ *)ALLOC_new(&RET_fl)
#define RET_destroy(x)      ALLOC_destroy(&RET_fl,(Freelist *)x)

#define INCR_new()      (struct Increment_ *)ALLOC_new(&INCR_fl)
#define INCR_destroy(x)     ALLOC_destroy(&INCR_fl,(Freelist *)(char *)x)

#define ASSIGNget_lhs(s)    ((s)->u.assign->lhs)
#define ASSIGNget_rhs(s)    ((s)->u.assign->rhs)
#define CASEget_selector(s) ((s)->u.Case->selector)
#define CASEget_items(s)    ((s)->u.Case->cases)
#define COMP_STMTget_items(s)   ((s)->u.compound->statements)
#define CONDget_condition(s)    ((s)->u.cond->test)
#define CONDget_then_clause(s)  ((s)->u.cond->code)
#define CONDget_else_clause(s)  ((s)->u.cond->otherwise)
#define LOOPget_while(s)    ((s)->u.loop->while)
#define LOOPget_until(s)    ((s)->u.loop->until)
#define LOOPget_body(s)     ((s)->u.loop->statement)
#define PCALLget_procedure(s)   ((s)->u.proc->procedure)
#define PCALLget_parameters(s)  ((s)->u.proc->parameters)
#define RETget_expression(s)    ((s)->u.ret->value)

/***********************/
/* function prototypes */
/***********************/

extern SC_EXPRESS_EXPORT Statement    STMTcreate( int );
extern SC_EXPRESS_EXPORT Statement    ALIAScreate( struct Scope_ *, Variable, Linked_List );
extern SC_EXPRESS_EXPORT Statement    CASEcreate( Expression , Linked_List );
extern SC_EXPRESS_EXPORT Statement    ASSIGNcreate( Expression , Expression );
extern SC_EXPRESS_EXPORT Statement    COMP_STMTcreate( Linked_List );
extern SC_EXPRESS_EXPORT Statement    CONDcreate( Expression, Linked_List, Linked_List );
extern SC_EXPRESS_EXPORT Statement    LOOPcreate( struct Scope_ *, Expression, Expression, Linked_List );
extern SC_EXPRESS_EXPORT Statement    PCALLcreate( Linked_List );
extern SC_EXPRESS_EXPORT Statement    RETcreate( Expression );
extern SC_EXPRESS_EXPORT void     STMTinitialize( void );
extern SC_EXPRESS_EXPORT struct Scope_ * INCR_CTLcreate( Symbol *, Expression start,
        Expression end, Expression increment );

#endif /*STATEMENT_H*/
