// eval6.h

#ifndef __EVAL6_H__
#define __EVAL6_H__

class proglet_t {
public:
   typedef enum {unknown_e, WantMore_e, run_e, SyntaxError_e} ParseStatus_t;
   typedef double	value_t;

private:
   enum {
      MaxTokenLen    =  10,
      MaxStackDepth  =  10,
      MaxSymbols     =  20,
      MaxProgLen     = 100,
      MaxLoopDepth   =   5
   };

   typedef enum {
      UnknownS_e,
      warn_e,     // Discard statement, but continue program.
      stop_e      // Terminate program.
   } severity_t;

   typedef char   token_t[MaxTokenLen+1]; // Leave one extra character for the terminating null.

   typedef enum {
      unknown_tok,    ident_tok,      number_tok,     null_tok,
      if_tok,         then_tok,       else_tok,       endif_tok,
      loop_tok,       endloop_tok,    exit_tok,       when_tok,
      unless_tok,     print_tok,      run_tok,
      lt_tok, le_tok, eq_tok, ne_tok, gt_tok, ge_tok,
      BoolAnd_tok,    BoolOr_tok,     BoolNot_tok,
      BitAnd_tok,     BitOr_tok,      BitNot_tok,
      plus_tok,       minus_tok,      mul_tok,        div_tok,
      mod_tok,        rem_tok,        Lshift_tok,     Rshift_tok,
      asgn_tok,       PlusAsgn_tok,   MinusAsgn_tok,
      pow_tok,        Lpar_tok,       Rpar_tok,       comma_tok,
      label_tok,      StmtDelim_tok,  include_tok,    dot_tok
   } TokenType_t;

//   typedef double	value_t;

   typedef enum {
      function_e,
      constant_e,
      variable_e
   } SymType_t;      // Symbol types.

   typedef struct {
      token_t     name;
      SymType_t   type;
      value_t     value;
   } symbol_t;

   typedef enum {
         unknown_instr,
         PushNum_instr, PushSym_instr,                         // Primary stack operations.
         UnaryMinus_instr, BitNot_instr,                       // Unary arithmetic operations.
         add_instr,     mul_instr,     sub_instr,  div_instr,  // Binary arithmetic operations.
         BitAnd_instr,  BitOr_instr,
         pow_instr,     mod_instr,     rem_instr,
         Lshift_instr,  Rshift_instr,
         BoolAnd_instr, BoolOr_instr,  BoolNot_instr,
         lt_instr, le_instr, eq_instr, ne_instr, gt_instr, ge_instr,
         rand_instr,                                           // Functions of 0 variables.
         abs_instr,                                            // Functions of 1 variable.
         sin_instr,     cos_instr,  tan_instr,
         asin_instr,    acos_instr, atan_instr,
         atan2_instr,                                          // Functions of 2 variables.
         print_instr,
         asgn_instr,    PlusAsgn_instr, MinusAsgn_instr,       // Statements.
         if_instr,      jump_instr,
         loop_instr, exit_instr, when_instr, unless_instr
   } instr_t;

   typedef union {
      instr_t  instr;
      symbol_t *sym;
      value_t  num;
      int      address;
   } program_t;

   int         LoopDepth;
   struct {
      int      StartAddress;
      token_t  name;
   } LoopStack[MaxLoopDepth];

   char        *statement;
   int         StmtLen,
               StmtIndex;

   token_t     token;
   value_t     TokenValue;
   TokenType_t TokenType;

   value_t     stack[MaxStackDepth];
   int         StackDepth;
   symbol_t    symbols[MaxSymbols];
   int         NumFunctions,
               NumSymbols,
               ProgLen;

   program_t   *prog;

   bool           equal (token_t a, token_t b);
   void           error (severity_t severity, char *msg1, char *msg2 = 0, char *msg3 = 0);
   void           AddInstr (instr_t instr);
   void           AddInstr (value_t num);
   void           AddInstr (instr_t instr, symbol_t *sym);
   void           AddInstr (instr_t instr, int addr);
   symbol_t       *FindSymbol (token_t name);
   symbol_t       *CreateSymbol (token_t name, SymType_t type, value_t value = 0.0);
   value_t        GetValue (token_t name, bool AllowFunctions);
   TokenType_t    FollowedBy (char next, char follow1, TokenType_t op1, char follow2, TokenType_t op2, TokenType_t op3);
   TokenType_t    FollowedBy (char next, char follow1, TokenType_t op1, TokenType_t op2);
   void           GetNextToken (void);
   void           InitLexer (char *line);
   int            ParseArithExprList (TokenType_t EndToken);

   void           ParsePrimary (void);
   void           ParseNegExpr (void);
   void           ParsePowExpr (void);
   void           ParseMulExpr (void);
   void           ParseAddExpr (void);
   void           ParseBitAndExpr (void);
   void           ParseBitOrExpr(void);
   void           ParseArithExpr(void) { ParseBitOrExpr (); };

   void           ParseBoolPrimaryExpr (void);
   void           ParseBoolNegExpr (void);
   void           ParseBoolAndExpr (void);
   void           ParseBoolOrExpr (void);
   void           ParseBoolExpr(void) { ParseBoolOrExpr (); };

   void           ParseAssignment (void);
   void           ParsePrint (void);
   void           ParseExit (void);
   void           ParseLoop (void);
   void           ParseInclude (void);
   void           ParseIf (void);
   bool           ParseStatement (void);
   void           ParseStmtList (void);
   void           InitSymbolTable (void);
   void           push (value_t v);
   value_t        pop (void);
   void           CheckStackDepth (char *OpName);
   bool           dump (program_t *prog, int ProgLen);// Disassemble a subroutine.
   bool           run  (program_t *prog, int ProgLen);// Run a subroutine.

public:  // The public interface for the proglet class.
   proglet_t ();                             // Constructor.
   ~proglet_t ();                            // Destructor.
   void           reinit (void);             // For re-using a proglet.
   ParseStatus_t  ParseBlock (char *line, int *MaxArgs = 0, value_t *args = 0);
   ParseStatus_t  ParseFile  (char *line, int *MaxArgs = 0, value_t *args = 0);
   bool           dump   (void);             // Disassemble a compiled proglet.
   bool           run    (value_t time = 0);   // Run a proglet.
};

#endif

