/* Copyright Per Bothner 1987. Read the file Q-INFO */
#ifndef PARSEFILE_H
#define PARSEFILE_H
#include <stdio.h>
/*#include <expression.h>*/
/*#define IsMacro(m) (MemGetType(m)==MacroT)*/
#define CharExtract(ch) (*SymbolUnsignedString((Symbol*)ch))
#ifdef __cplusplus
#include "genfiles.h"
#endif

#include "parsestream.h"
#include "expression.h"

typedef struct
  {
    short rPriority;	/* integer, or MacroProc or MacroExpr */
    Func postfix;
    Object defaultRight; /* a value, or NULL, or FuncDefault or NoDefault */
  } PlainOp;

#define FuncDefault ((Object)1)	/*with no right operand of f, use $;x$ f x */
#define NoDefault ((Object)3)	/* operand \must/ have a right operand */
#define IsMacroOp(op) ((op)->rPriority & 0x1000)
#define MacroProc 0x1001
#define MacroExpr 0x1002

/* #define NEW_BLOCK */

#define AtLeastOnePrio 4	/* get at least one token; may be OR'd in */
/* parse priorities: last argument to ParseScan and ParseLook.
 * In general, higher values mean "read more".
 */
/*#define EOFprio  0xFF0*/
#define PARprio  0x600
#define EOMprio  0x500
#define CMDprio  (EOLprio+1) /* Same as EOLprio, but accept excess ')' */
#define EOLprio  0x400 /* Read upto '\n' (exclusive) */
/* Note (exclusive) used to be (inclusive); some code may need fixing. */
#define DEFprio  0x300 /* Read upto ';' or '\n' (exclusive) */
#define WRDprio  0x100
/* An operator (e.g. arithmetic-) with priority 'p' (1..15) has
 * parse-priority 'p*0x10' or 'WRDprio+p*0x10'. The former means
 * only parse upto next white space, while the latter means that
 * multiple words may be parsed, since the priority of horizontal
 * white space can be said to be WRDprio. */
#define PrioMask 0xFF0
#define DefaultPrio 3
#define ONEprio ((DefaultPrio<<4)+AtLeastOnePrio)	/* get at one token */

#define IsNullExpr(x) ((x) == NullExpr || (x) == FailedParse)
#define SIGNAL_FailedParse return FailedParse

#define SourceLocation(ff) ((ff)->sourcePos)

#define ParseBufSize 1
#define DefaultParseLineSize 160

struct ParseFile; struct streambuf;

#if 0
struct PushedParseFile {
    /* This is created when a new file is included */
    /* It is used to save information about the old file */
    struct PushedParseFile *pushedFile;
    FILE *file;
    struct Location sourcePos;
    char *line;
    int offset, fence, size;
    char *source_file_name;
    int (*OLD_getLine)(struct ParseFile*); /* fill buffer with characters. return 0 at EOF */
    FILE *promptFile;
    char *promptFormat;
};
#endif

#if 0
class parsestream : public istream {
    streammarker marks[2];
    short _first; // of the two marks; either 0 or 1
    int _lineno;
    int first() { return _first; }
    int second() { return 1-_first; }
    int line_length() { marks[second].delta(marks[first]); }
    int seek_in_line(int i);
    int tell_in_line();
    int line_number();
};
#endif

struct ParseFile : public InStream {
    unsigned char terminators;
    char errors;
    short nesting; /* Number of surrounding () or ~ */
    FILE *promptFile;
    struct Expression *cur; /* currently only used when calling a macro */
    struct Expression *left;
    struct Block *block, *saveBlock;
    struct Module *module;
    struct Block *defaultReturn; /* destination for RETURN expressions */
    struct Location sourcePos;
    struct Identifier *identifiers; /* chronological list of Identifiers */
    struct BlockSave *blocksave;
    char *source_file_name;
    struct ProcExpr *cur_proc;
    const StringC * nesting_kind; // E.g. "()" when inside parens.
    struct PushedParseFile *pushedFile;
    DeclList unclaimed_decls;
    ParseFile(parsebuf *str=NULL);
    parsebuf* pbuf() { return (parsebuf*)stream; }
//  protected:
//    virtual int underflow(); // Should actually be in streambuf.
};

struct BlockSave {
    struct BlockSave *prev;
    struct Block *saveBlock;
    struct ParseFile *ff;
    int statementDelim;
    struct Identifier *identifiers;
    DeclListMark decls;
};

#define ParseLParenSinceSpace 1 /* have seen '(' more recently than ' ' */
#define ParseInParamList 2
#define TerminatorIF 4
#define DebugParse 8
#define ParsePeekOK 16
#define ParseEOFseen 64
#define ParseAcceptRParen 128 /* accept unmatched ')' without complaining */

/* bits in 'bits' field of Expr */
/* #define ExprUserParens 1 * parens surround expr */
#define ExprStruct 2		/* Expr should evaluate to a Struct */

extern struct HashTable *MacroTab;

extern unsigned char CharType[];
#define NUM 1	/* 0..9 */
#define UC 2	/* A..Z */
#define LC 4	/* a..z */
#define HW 8	/* horizontal white space */
#define SY 16
#define AUX 32	/* other symbols to treat as letters i.e. '.' and '_' */
#define VW 64	/* vertical white space */
#define MAG 128	/* special characters */
#define Numeric(ch) (CharType[ch]&NUM)
#define HorizontalWhite(ch) (CharType[ch]&HW)
#define WhiteSpace(ch) (CharType[ch]&(HW|VW))
#define LowerCaseLet(ch) (CharType[ch]&LC)
#define UpperCaseCh(ch) (CharType[ch]&UC)
#define Letter(ch) (CharType[ch]&(UC|LC|AUX))
#define Alphameric(ch) (CharType[ch]&(UC|LC|NUM|AUX))
#define Special(ch) (CharType[ch]&SY)
#define CommentChar '#'
#define UnquoteChar '$'

/* prompts typed to the user */
#define StandardPrompt "*: "
#define NoValPrompt " : "
#define ContinuationPrompt "-: "
#define TextPrompt "\"> "

struct StringPair {
    char *data;
    size_t length;
#define StringsDone ((size_t)(-1))
#ifdef __cplusplus
    inline int done() { return length == StringsDone; }
    inline void set_done() { length = StringsDone; }
#endif
};

#define IdentifierMacro 1
#ifdef __cplusplus
typedef Expression *(*ParseFunction)(struct ParseFile*);
typedef struct Macro
  {
    struct Macro *anext, *aprev; /* in alphabethical order */
    Symbol * name;
    char nEqual; /* number of equal chars with next */
    char flags;
    ParseFunction command;
    char lprio, rprio;
  } MacroEntry;
#define MACRO_NEXT(m) ((m)->anext)
#define MACRO_PREV(m) ((m)->aprev)
#define MACRO_NAME(m) ((m)->name)
#define MACRO_FLAGS(m) ((m)->flags)
#define MACRO_LPRIO(m) ((m)->lprio)
#define MACRO_RPRIO(m) ((m)->rprio)
#define MACRO_COMMAND(m) ((m)->command)
#define MACRO_NEQUAL(m) ((m)->nEqual)
#define MACRO_STRING(m) SymbolString(MACRO_NAME(m))
#define MACRO_LENGTH(m) SymbolLength(MACRO_NAME(m))
extern struct MacroTable *QStdMacros;
struct MacroTable
  {
#ifdef COMPILER
    MacroEntry head[1];
#define MACRO_HEAD(mtab) ((mtab)->head)
#else /*not COMPILER*/
    MacroEntry *afirst, *alast; /* must match anext and aprev */
    Symbol * name;
    char nEqual; /* must be zero */
    char filler;
#define MACRO_HEAD(mtab) ((MacroEntry*)(mtab))
/*  Fields up to here must match struct Macro */
#endif /*COMPILER*/
    short nIndex;
    struct MacroTable *other;	/* if no command found try this table */
    MacroEntry *(index[1]);	/* nIndex+1 elements */
/* index[ch>=nIndex ? nIndex : ch] points to first Macro whose name[0] >= ch */
  };

extern void ParseError(struct ParseFile *ff, char *format, ...);
extern Expr * ParseScan(Expr *left, struct ParseFile *ff, int prio);
extern Expr * Parse(FILE *f, struct Module *module, Object env);
extern struct ExprList * ParseWord(struct ParseFile *ff, int look_ahead = -1);
extern Expr *ParseCommand(struct ParseFile*);
extern int EvalExOffset;
extern int CompilePrimitiveData;
extern Expr * ParseLookEOF(struct ParseFile *ff);
extern Expr * ParseLook(struct ParseFile *ff, int prio);
extern Expr *ParseComment(struct ParseFile *ff);
extern Expr * ParseNumeric(struct ParseFile *ff, int ch = -1);
extern Expr * ParseOne(struct ParseFile *ff, int prio);
extern Expr * ParseIndex(struct ParseFile *ff);
extern ExprList * ParseList(struct ParseFile *ff, int prio = PARprio);
extern Expr * ParseBlock(struct ParseFile *ff, int prio);
extern void TestPushBlock(struct BlockSave *save, struct ParseFile *ff);
extern void TestPopBlock(struct BlockSave *save);
extern void PushParseFile(struct ParseFile *ff, parsebuf*, char *name);
extern Symbol * GetName(struct ParseFile*);
extern Symbol * ParseIdent(register struct ParseFile *ff);
extern struct ProcExpr *
  ParseFunctionPattern(struct ParseFile *ff, Symbol **pname, int isClassDef);
extern Expr * ParseIf(struct ParseFile *ff);
extern Expr* ParseString(char *str, int len, Module *module);
/*extern struct Statement *
  AppendStatement(struct Block *, struct Declaration *, Expr *);*/
extern struct Statement * AppendStatement(struct Block *block, Expr *exp);
extern int ScanBlanks(struct ParseFile *ff, int skip_new_lines=0);
void AddIdentifier(struct Identifier *, struct ParseFile *ff, enum Privacy);
extern void AppendDeclChain(Block* block, ParseFile* ff, Declaration**& end);
struct Identifier *
  AddIdentifier(Symbol *name, struct ParseFile *ff, enum Privacy privacy);
extern Expr *GetUnquotedPart(struct ParseFile *ff);
extern struct Identifier * ParseIdentifier(ParseFile* ff);
extern struct ParseFile * OpenParseFile(parsebuf *, struct Module *);
extern void BindClause(struct ProcExpr *proc);
extern ParseFile * OpenParseInteractive();
extern int CurIndentation(ParseFile *ff);
//EXTERN Symbol * GetParseChar(struct ParseFile *);
#endif
#endif /*PARSEFILE_H*/
