/* Character classification, used by both Q and Lisp/Scheme parsers. */

enum ReadCode {
    ReadIllegal,
    ReadHSpace, // Horizonal space: ' ', '\t'
    ReadVSpace, // Vertical space: CR NL FF VT
    ReadTMacro, // Terminating macro character
    ReadNMacro, // Non-terminating macro character
    ReadSEscape, // Single escape character
    ReadMEscape, // Multiple escape character
    ReadDigit,
    ReadLetter,
    ReadWord,
    ReadStatementSep, // For Q: ';'
    ReadDeclPrefix, // For Q: ':
    ReadRParen, // For Q: ')'
};

#define Rep2(ENTRY) ENTRY, ENTRY
#define Rep4(ENTRY) Rep2(ENTRY), Rep2(ENTRY)
#define Rep8(ENTRY) Rep4(ENTRY), Rep4(ENTRY)

class InStream; class ParseFile; class Expr;
/* At some point, perhaps merge (some of?) these. */
typedef Root* (*ReadMacroFunction)(InStream*, char); /* For Lisp */
typedef Expr* (*QMacroFunction)(ParseFile*); /* For Q */
typedef Root* (*ReadDispatchingFunction)(InStream*, char, int);

struct ReadEntry {
    enum ReadCode code;
};

struct LReadEntry : public ReadEntry {
    ReadMacroFunction func;
    LReadEntry(enum ReadCode c, ReadMacroFunction f) { code = c; func = f; }
};

struct QReadEntry  : public ReadEntry {
    QMacroFunction func;
    QReadEntry(enum ReadCode c, QMacroFunction f) { code = c; func = f; }
};

struct QReadIdMacro : public QReadEntry {
    Symbol& name;
    QReadIdMacro(Symbol& n, QMacroFunction f);
};

extern ReadEntry R_Illegal, R_HSpace, R_VSpace,
    R_Digit, R_Letter, R_Word, R_SEscape;

#define LispReadScheme 1 // Prefer Scheme
#define LispReadDotOk 2 // . is ok
#define LispReadPreservingWhitespace 4
#define LispReadRecursive 8
#define LispReadForceSymbol 16 // Force a symbol to be read, as if after '\\'

extern char *(LispCharNames[]);

extern Root* LispRead(InStream * stream, int options);
