//
// Copyright (c) Microsoft Corporation 1995
//
// ast.h
//
// Header file for the abstract syntax tree.
//
// History:
//  05-20-95 ScottH     Created
//

#ifndef __AST_H__
#define __AST_H__

typedef struct tagASTEXEC * PASTEXEC;


//
// AST 
//

typedef enum 
    {
    AT_BASE,
    
    AT_MODULE_DECL,
    AT_PROC_DECL,

    AT_ENTER_STMT,
    AT_LEAVE_STMT,    
    AT_ASSIGN_STMT,
    AT_HALT_STMT,
    AT_LABEL_STMT,
    AT_GOTO_STMT,
    AT_TRANSMIT_STMT,
    AT_WAITFOR_STMT,
    AT_DELAY_STMT,
    AT_SET_STMT,
    AT_WHILE_STMT,
    AT_IF_STMT,
    
    AT_INT_EXPR,
    AT_STRING_EXPR,
    AT_VAR_EXPR,
    AT_BOOL_EXPR,
    AT_UNOP_EXPR,
    AT_BINOP_EXPR,
    AT_GETIP_EXPR,
    } ASTTYPE;


// Basic AST 

typedef struct tagAST
    {
    DWORD   cbSize;
    ASTTYPE asttype;
    DWORD   iLine;
    } AST;                            // Basic AST
DECLARE_STANDARD_TYPES(AST);

#define Ast_GetSize(p)      (((PAST)(p))->cbSize)
#define Ast_GetType(p)      (((PAST)(p))->asttype)
#define Ast_GetLine(p)      (((PAST)(p))->iLine)

#define Ast_SetSize(p, s)   (((PAST)(p))->cbSize = (s))
#define Ast_SetType(p, t)   (((PAST)(p))->asttype = (t))
#define Ast_SetLine(p, v)   (((PAST)(p))->iLine = (v))

RES     PUBLIC Ast_New(LPVOID * ppv, ASTTYPE asttype, DWORD cbSize, DWORD iLine);
void    PUBLIC Ast_Delete(PAST this);
RES     PUBLIC Ast_Dup(PAST this, PAST * ppast);

#ifdef DEBUG
void    PUBLIC Ast_Dump(PAST this);
#else
#define Ast_Dump(past)    
#endif

// Decl

typedef struct tagDECL
    {
    AST     ast;
    PSYMTAB pst;        // symbol table
    } DECL;
DECLARE_STANDARD_TYPES(DECL);

RES     PUBLIC Decl_Delete(PDECL this);
void    CALLBACK Decl_DeletePAPtr(LPVOID pv, LPARAM lparam);

// Proc Declaration 

typedef struct tagPROCDECL
    {
    DECL    decl;
    LPSTR   pszIdent;
    HPA     hpaStmts;
    PSYMTAB pst;
    } PROCDECL;
DECLARE_STANDARD_TYPES(PROCDECL);

RES     PUBLIC ProcDecl_New(PDECL * ppdecl, LPCSTR pszIdent, HPA hpa, PSYMTAB pst, DWORD iLine);

#define ProcDecl_GetIdent(p)        (((PPROCDECL)(p))->pszIdent)
#define ProcDecl_GetSymtab(p)       (((PPROCDECL)(p))->pst)


// Module Declaration 

typedef struct tagMODULEDECL
    {
    DECL    decl;
    HPA     hpaProcs;
    PSYMTAB pst;
    } MODULEDECL;
DECLARE_STANDARD_TYPES(MODULEDECL);

RES     PUBLIC ModuleDecl_New(PDECL * ppdecl, HPA hpa, PSYMTAB pst, DWORD iLine);
RES     PUBLIC ModuleDecl_Parse(PMODULEDECL * ppmoduledecl, PSCANNER pscanner, PSYMTAB pst);
RES     PUBLIC ModuleDecl_Typecheck(PMODULEDECL this, HSA hsaStxerr);
RES     PUBLIC ModuleDecl_Codegen(PMODULEDECL this, PASTEXEC pastexec);

#define ModuleDecl_GetSymtab(p)     (((PMODULEDECL)(p))->pst)


// Expressions

typedef struct tagEXPR
    {
    AST     ast;
    DATATYPE dt;
    DWORD   dwFlags;        // EF_*
    EVALRES er;             // Used when evaluated at runtime
    } EXPR;
DECLARE_STANDARD_TYPES(EXPR);

// Expression flags
#define EF_DEFAULT      0x0000
#define EF_DONE         0X0001
#define EF_ALLOCATED    0x0002

RES     PUBLIC Expr_Eval(PEXPR this, PASTEXEC pastexec);
RES     PUBLIC Expr_Delete(PEXPR this);
void    CALLBACK Expr_DeletePAPtr(LPVOID pv, LPARAM lparam);

#define Expr_GetDataType(p)         (((PEXPR)(p))->dt)
#define Expr_GetRes(p)              (&((PEXPR)(p))->er)

#define Expr_SetDataType(p, x)      (((PEXPR)(p))->dt = (x))
#define Expr_SetDone(p)             SetFlag(((PEXPR)(p))->dwFlags, EF_DONE)
#define Expr_SetRes(p, x)           (Expr_SetDone(p),((PEXPR)(p))->er.dw = (DWORD)(x))


// Integer Expression

typedef struct tagINTEXPR
    {
    EXPR    expr;
    int     nVal;       // signed value by design
    } INTEXPR;
DECLARE_STANDARD_TYPES(INTEXPR);

RES     PUBLIC IntExpr_New(PEXPR * ppexpr, int nVal, DWORD iLine);

#define IntExpr_GetVal(p)           (((PINTEXPR)(p))->nVal)

#define IntExpr_SetVal(p, n)        (((PINTEXPR)(p))->nVal = (n))


// String Expression

typedef struct tagSTREXPR
    {
    EXPR    expr;
    LPSTR   psz;
    } STREXPR;
DECLARE_STANDARD_TYPES(STREXPR);

RES     PUBLIC StrExpr_New(PEXPR * ppexpr, LPCSTR psz, DWORD iLine);

#define StrExpr_GetStr(p)           (((PSTREXPR)(p))->psz)

#define StrExpr_SetStr(p, n)        (((PINTEXPR)(p))->nVal = (n))


// Bool Expression

typedef struct tagBOOLEXPR
    {
    EXPR    expr;
    BOOL    bVal;
    } BOOLEXPR;
DECLARE_STANDARD_TYPES(BOOLEXPR);

RES     PUBLIC BoolExpr_New(PEXPR * ppexpr, BOOL bVal, DWORD iLine);

#define BoolExpr_GetVal(p)          (((PBOOLEXPR)(p))->bVal)

#define BoolExpr_SetVal(p, b)       (((PBOOLEXPR)(p))->bVal = (b))


// Variable Expression

typedef struct tagVAREXPR
    {
    EXPR    expr;
    LPSTR   pszIdent;
    } VAREXPR;
DECLARE_STANDARD_TYPES(VAREXPR);

RES     PUBLIC VarExpr_New(PEXPR * ppexpr, LPCSTR pszIdent, DWORD iLine);

#define VarExpr_GetIdent(p)         (((PVAREXPR)(p))->pszIdent)


// Binary Operation Expression

typedef enum
    {
    // WARNING: These types must match the order of their 
    // corresponding SYM and OP values.

    BOT_OR,
    BOT_AND,

    BOT_LEQ,        
    BOT_LT,         
    BOT_GEQ,        
    BOT_GT,         
    BOT_NEQ,
    BOT_EQ,

    BOT_PLUS,
    BOT_MINUS,
    BOT_MULT,
    BOT_DIV,

    } BINOPTYPE;

typedef struct tagBINOPEXPR
    {
    EXPR    expr;
    BINOPTYPE binoptype;
    PEXPR   pexpr1;
    PEXPR   pexpr2;
    } BINOPEXPR;
DECLARE_STANDARD_TYPES(BINOPEXPR);

RES     PUBLIC BinOpExpr_New(PEXPR * ppexpr, BINOPTYPE binoptype, PEXPR pexpr1, PEXPR pexpr2, DWORD iLine);

#define BinOpExpr_GetType(p)        (((PBINOPEXPR)(p))->binoptype)
#define BinOpExpr_GetExpr1(p)       (((PBINOPEXPR)(p))->pexpr1)
#define BinOpExpr_GetExpr2(p)       (((PBINOPEXPR)(p))->pexpr2)

#define BinOpExpr_SetType(p, t)     (((PBINOPEXPR)(p))->binoptype = (t))
#define BinOpExpr_SetRes(p, x)      (((PBINOPEXPR)(p))->er.dw = (DWORD)(x))


// Unary Operation Expression

typedef enum
    {
    UOT_NEG,
    UOT_NOT,
    UOT_GETIP,
    } UNOPTYPE;

typedef struct tagUNOPEXPR
    {
    EXPR    expr;
    UNOPTYPE unoptype;
    PEXPR   pexpr;
    EVALRES er;         // Used for UOT_GETIP on strings
    } UNOPEXPR;
DECLARE_STANDARD_TYPES(UNOPEXPR);

RES     PUBLIC UnOpExpr_New(PEXPR * ppexpr, UNOPTYPE unoptype, PEXPR pexpr, DWORD iLine);

#define UnOpExpr_GetType(p)         (((PUNOPEXPR)(p))->unoptype)
#define UnOpExpr_GetExpr(p)         (((PUNOPEXPR)(p))->pexpr)

#define UnOpExpr_SetType(p, t)      (((PUNOPEXPR)(p))->unoptype = (t))
#define UnOpExpr_SetRes(p, x)       (((PUNOPEXPR)(p))->er.dw = (DWORD)(x))


// Statements

typedef struct tagSTMT
    {
    AST     ast;
    } STMT;
DECLARE_STANDARD_TYPES(STMT);

RES     PUBLIC Stmt_Delete(PSTMT this);
void    CALLBACK Stmt_DeletePAPtr(LPVOID pv, LPARAM lparam);

RES     PUBLIC Stmt_Exec(PSTMT this, PASTEXEC pastexec);


// Enter Statement

typedef struct tagENTERSTMT
    {
    STMT    stmt;
    PSYMTAB pst;
    } ENTERSTMT;
DECLARE_STANDARD_TYPES(ENTERSTMT);

RES     PUBLIC EnterStmt_New(PSTMT * ppstmt, PSYMTAB pst, DWORD iLine);

#define EnterStmt_GetSymtab(p)      (((PENTERSTMT)(p))->pst)


// Leave Statement

typedef struct tagLEAVESTMT
    {
    STMT    stmt;
    } LEAVESTMT;
DECLARE_STANDARD_TYPES(LEAVESTMT);

RES     PUBLIC LeaveStmt_New(PSTMT * ppstmt, DWORD iLine);


// Halt Statement

typedef struct tagHALTSTMT
    {
    STMT    stmt;
    } HALTSTMT;
DECLARE_STANDARD_TYPES(HALTSTMT);

RES     PUBLIC HaltStmt_New(PSTMT * ppstmt, DWORD iLine);


// Assignment Statement

typedef struct tagASSIGNSTMT
    {
    STMT    stmt;
    LPSTR   pszIdent;
    PEXPR   pexpr;
    } ASSIGNSTMT;
DECLARE_STANDARD_TYPES(ASSIGNSTMT);

RES     PUBLIC AssignStmt_New(PSTMT * ppstmt, LPCSTR pszIdent, PEXPR pexpr, DWORD iLine);

#define AssignStmt_GetIdent(p)          (((PASSIGNSTMT)(p))->pszIdent)
#define AssignStmt_GetExpr(p)           (((PASSIGNSTMT)(p))->pexpr)


// While Statement

typedef struct tagWHILESTMT
    {
    STMT    stmt;
    PEXPR   pexpr;
    HPA     hpaStmts;
    char    szTopLabel[MAX_BUF_KEYWORD];
    char    szEndLabel[MAX_BUF_KEYWORD];
    } WHILESTMT;
DECLARE_STANDARD_TYPES(WHILESTMT);

RES     PUBLIC WhileStmt_New(PSTMT * ppstmt, PEXPR pexpr, HPA hpaStmts, LPCSTR pszTopLabel, LPCSTR pszEndLabel, DWORD iLine);

#define WhileStmt_GetExpr(p)            (((PWHILESTMT)(p))->pexpr)
#define WhileStmt_GetStmtBlock(p)       (((PWHILESTMT)(p))->hpaStmts)
#define WhileStmt_GetTopLabel(p)        (((PWHILESTMT)(p))->szTopLabel)
#define WhileStmt_GetEndLabel(p)        (((PWHILESTMT)(p))->szEndLabel)

// If Statement

typedef struct tagIFSTMT
    {
    STMT    stmt;
    PEXPR   pexpr;
    HPA     hpaStmts;
    char    szElseLabel[MAX_BUF_KEYWORD];
    char    szEndLabel[MAX_BUF_KEYWORD];
    } IFSTMT;
DECLARE_STANDARD_TYPES(IFSTMT);

RES     PUBLIC IfStmt_New(PSTMT * ppstmt, PEXPR pexpr, HPA hpaStmts, LPCSTR pszElseLabel, LPCSTR pszEndLabel, DWORD iLine);

#define IfStmt_GetExpr(p)               (((PIFSTMT)(p))->pexpr)
#define IfStmt_GetStmtBlock(p)          (((PIFSTMT)(p))->hpaStmts)
#define IfStmt_GetElseLabel(p)          (((PIFSTMT)(p))->szElseLabel)
#define IfStmt_GetEndLabel(p)           (((PIFSTMT)(p))->szEndLabel)

// Label Statement

typedef struct tagLABELSTMT
    {
    STMT    stmt;
    LPSTR   psz;
    } LABELSTMT;
DECLARE_STANDARD_TYPES(LABELSTMT);

RES     PUBLIC LabelStmt_New(PSTMT * ppstmt, LPCSTR psz, DWORD iLine);

#define LabelStmt_GetIdent(p)       (((PLABELSTMT)(p))->psz)


// Goto Statement

typedef struct tagGOTOSTMT
    {
    STMT    stmt;
    LPSTR   psz;
    } GOTOSTMT;
DECLARE_STANDARD_TYPES(GOTOSTMT);

RES     PUBLIC GotoStmt_New(PSTMT * ppstmt, LPCSTR psz, DWORD iLine);

#define GotoStmt_GetIdent(p)        (((PGOTOSTMT)(p))->psz)


// Delay Statement

typedef struct tagDELAYSTMT
    {
    STMT    stmt;
    PEXPR   pexprSecs;
    } DELAYSTMT;
DECLARE_STANDARD_TYPES(DELAYSTMT);

RES     PUBLIC DelayStmt_New(PSTMT * ppstmt, PEXPR pexprSecs, DWORD iLine);

#define DelayStmt_GetExpr(p)        (((PDELAYSTMT)(p))->pexprSecs)


// WaitFor Statement

typedef struct tagWAITCASE
    {
    PEXPR   pexpr;
    LPSTR   pszIdent;           // label to jump to; may be NULL
    DWORD   dwFlags;            // WCF_*
    } WAITCASE;
DECLARE_STANDARD_TYPES(WAITCASE);

// Flags for WaitforStmt
#define WCF_DEFAULT     0x0000
#define WCF_MATCHCASE   0x0001

RES     PUBLIC Waitcase_Create(PHSA phsa);
RES     PUBLIC Waitcase_Add(HSA hsa, PEXPR pexpr, LPCSTR pszIdent, DWORD dwFlags);
RES     PUBLIC Waitcase_Destroy(HSA hsa);

typedef struct tagWAITFORSTMT
    {
    STMT    stmt;
    HSA     hsa;                // List of strings to wait for
    PEXPR   pexprUntil;         // Optional; may be NULL
    } WAITFORSTMT;
DECLARE_STANDARD_TYPES(WAITFORSTMT);

RES     PUBLIC WaitforStmt_New(PSTMT * ppstmt, HSA hsa, PEXPR pexprUntil, DWORD iLine);

#define WaitforStmt_GetCaseList(p)  (((PWAITFORSTMT)(p))->hsa)
#define WaitforStmt_GetUntilExpr(p) (((PWAITFORSTMT)(p))->pexprUntil)


// Transmit Statement

typedef struct tagTRANSMITSTMT
    {
    STMT    stmt;
    PEXPR   pexpr;
    DWORD   dwFlags;        // TSF_*
    } TRANSMITSTMT;
DECLARE_STANDARD_TYPES(TRANSMITSTMT);

// Flags for TransmitStmt
#define TSF_DEFAULT     0x0000
#define TSF_RAW         0x0001

RES     PUBLIC TransmitStmt_New(PSTMT * ppstmt, PEXPR pexpr, DWORD dwFlags, DWORD iLine);

#define TransmitStmt_GetExpr(p)     (((PTRANSMITSTMT)(p))->pexpr)
#define TransmitStmt_GetFlags(p)    (((PTRANSMITSTMT)(p))->dwFlags)


// Set Statement

typedef enum
    {
    ST_IPADDR,
    ST_PORT,
    ST_SCREEN,
    } SETTYPE;

typedef struct tagSETSTMT
    {
    STMT    stmt;
    SETTYPE settype;
    } SETSTMT;
DECLARE_STANDARD_TYPES(SETSTMT);

#define SetStmt_GetType(p)          (((PSETSTMT)(p))->settype)

#define SetStmt_SetType(p, t)       (((PSETSTMT)(p))->settype = (t))


// Set IP Statement

typedef struct tagSETIPSTMT
    {
    SETSTMT setstmt;
    PEXPR   pexpr;
    } SETIPSTMT;
DECLARE_STANDARD_TYPES(SETIPSTMT);

RES     PUBLIC SetIPStmt_New(PSTMT * ppstmt, PEXPR pexpr, DWORD iLine);

#define SetIPStmt_GetExpr(p)        (((PSETIPSTMT)(p))->pexpr)


// Set Port Statement

typedef struct tagPORTSTATE
    {
    DWORD   dwFlags;        // SPF_*
    BYTE    nDatabits;
    BYTE    nParity;        // 0-4: none, odd, even, mark, space
    BYTE    nStopbits;      // 0,1,2: 1 bit, 1.5 bits, 2 bits
    } PORTSTATE;
DECLARE_STANDARD_TYPES(PORTSTATE);

// Flags for PortState
#define SPF_DATABITS    0x0001
#define SPF_PARITY      0x0002
#define SPF_STOPBITS    0x0004

typedef struct tagSETPORTSTMT
    {
    SETSTMT setstmt;
    PORTSTATE portstate;
    } SETPORTSTMT;
DECLARE_STANDARD_TYPES(SETPORTSTMT);

RES     PUBLIC SetPortStmt_New(PSTMT * ppstmt, PPORTSTATE pstate, DWORD iLine);

#define SetPortStmt_GetFlags(p)     (((PSETPORTSTMT)(p))->portstate.dwFlags)
#define SetPortStmt_GetDatabits(p)  (((PSETPORTSTMT)(p))->portstate.nDatabits)
#define SetPortStmt_GetStopbits(p)  (((PSETPORTSTMT)(p))->portstate.nStopbits)
#define SetPortStmt_GetParity(p)    (((PSETPORTSTMT)(p))->portstate.nParity)


// Set Screen Statement

typedef struct tagSCREENSET
    {
    DWORD   dwFlags;        // SPF_*
    BOOL    fKBOn;          // TRUE/FALSE: on, off
    } SCREENSET;
DECLARE_STANDARD_TYPES(SCREENSET);

// Flags for Screen settings
#define SPF_KEYBRD      0x0001

typedef struct tagSETSCREENSTMT
    {
    SETSTMT setstmt;
    SCREENSET screenset;
    } SETSCREENSTMT;
DECLARE_STANDARD_TYPES(SETSCREENSTMT);

RES     PUBLIC SetScreenStmt_New(PSTMT * ppstmt, PSCREENSET pstate, DWORD iLine);

#define SetScreenStmt_GetFlags(p)   (((PSETSCREENSTMT)(p))->screenset.dwFlags)
#define SetScreenStmt_GetKeybrd(p)  (((PSETSCREENSTMT)(p))->screenset.fKBOn)



//
// AST execute block
//

#define MAX_BUF_IP  (3+1+3+1+3+1+3 + 1)

typedef struct tagASTEXEC
    {
    DWORD   dwFlags;
    HWND    hwnd;

    HANDLE  hport;
    PSESS_CONFIGURATION_INFO psci;
    HANDLE  hFindFmt;
    PSYMTAB pstSystem;      // Allocated: system symbol table

    HPA     hpaPcode;
    DWORD   ipaCur;         // current statement executing
    PSYMTAB pstCur;         // symbol table for current frame
    PSTMT   pstmtPending;   // pending statement 
    int     cProcDepth;     // call depth

    HSA     hsaStxerr;

    char    szIP[MAX_BUF_IP];
    int     nIter;          // scratch iterative value
    } ASTEXEC;
DECLARE_STANDARD_TYPES(ASTEXEC);

RES     PUBLIC Astexec_Init(PASTEXEC this, HANDLE hport, PSESS_CONFIGURATION_INFO psci, HSA hsaStxerr);
RES     PUBLIC Astexec_Destroy(PASTEXEC this);
RES     PUBLIC Astexec_Add(PASTEXEC this, PSTMT pstmt);
RES     PUBLIC Astexec_InsertLabel(PASTEXEC this, LPCSTR pszIdent, PSYMTAB pst);
RES     PUBLIC Astexec_JumpToLabel(PASTEXEC this, LPCSTR pszIdent);
void    PUBLIC Astexec_SetError(PASTEXEC this, BOOL bSuccess, BOOL bFailure);

RES     PUBLIC Astexec_Next(PASTEXEC this);
DWORD   PUBLIC Astexec_GetCurLine(PASTEXEC this);
void    PUBLIC Astexec_SendString(PASTEXEC this, LPCSTR pszSend, BOOL bRaw);
RES     PUBLIC Astexec_SetIPAddr(PASTEXEC this, LPCSTR psz);
RES     PUBLIC Astexec_FindFormat(PASTEXEC this, LPDWORD piFound);
RES     PUBLIC Astexec_DestroyFindFormat(PASTEXEC this);

// Flags for Astexec
#define AEF_DONE            0x0001
#define AEF_PAUSED          0x0002
#define AEF_HALT            0x0004
#define AEF_WAITUNTIL       0x0010
#define AEF_STOPWAITING     0x0020

#define Astexec_IsDone(this)            IsFlagSet((this)->dwFlags, AEF_DONE)
#define Astexec_IsReadPending(this)     (NULL != (this)->pstmtPending)
#define Astexec_IsPaused(this)          IsFlagSet((this)->dwFlags, AEF_PAUSED)
#define Astexec_IsHalted(this)          IsFlagSet((this)->dwFlags, AEF_HALT)
#define Astexec_IsWaitUntil(this)       IsFlagSet((this)->dwFlags, AEF_WAITUNTIL)

#define Astexec_GetIPAddr(this)         ((this)->szIP)
#define Astexec_GetPending(this)        ((this)->pstmtPending)

#define Astexec_ClearPause(this)        ClearFlag((this)->dwFlags, AEF_PAUSED)
#define Astexec_ClearWaitUntil(this)    ClearFlag((this)->dwFlags, AEF_WAITUNTIL)
#define Astexec_SetStopWaiting(this)    SetFlag((this)->dwFlags, AEF_STOPWAITING)

#define Astexec_SetIP(this, ipa)        ((this)->ipaCur = (ipa))
#define Astexec_SetHwnd(this, hwndT)    ((this)->hwnd = hwndT)
#define Astexec_SetPending(this, pstmt) ((this)->pstmtPending = (pstmt))

#endif // __AST_H__
