// eval6b.h

#ifndef __EVAL6B_H__
#define __EVAL6B_H__

class proglet_t {
public:  // The public interface for the proglet class.
	typedef enum {unknown_e, WantMore_e, run_e, SyntaxError_e} ParseStatus_t;
	typedef double	value_t;

	proglet_t ();									// Constructor.
	~proglet_t ();									// Destructor.
	void			reinit (bool more_func (void) = NULL);	// 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.

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		(*more) (void);	// Pointer to a function which will fetch more input.

	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.
};

#endif
