/* Copyright (c) 1993 by Sanjay Ghemawat */

#ifndef _LEXERH
#define _LEXERH

#include <string.h>

/*
 * Help in lexing.
 */

class charArray;

class Lexer {
  public:
    Lexer(char const* file);
    ~Lexer();

    /*
     * Status.
     */
    enum StatusType {
	Valid,
	Eof,
	Error
	};

    StatusType Status();		/* Get current status */

    void SetError(char const*);		/* Set error and corresponding msg */
    static char const* LastError();	/* Return text of last error */

    /*
     * Input operations.
     * Return true iff operation succeeded.
     * May have skipped undetermined amount of input in case of error.
     */

    /*
     * Character operations.
     */
    int Peek(char&);		/* Return next char without advancing */
    int Next(char&);		/* Return next char and advance over it */
    int Advance(char&);		/* Advance and then Peek() */


    /*
     * Skip past expected text.
     */
    int Skip(char);
    int Skip(char const*);

    /*
     * Skip all whitespace.
     */
    int SkipWS();

    /*
     * Read an identifier.
     * An identifier is a non-empty sequence of alphanumeric characters
     * (including underscores), where the first character is not a digit.
     * 
     * X is set to point to a temporary buffer managed by the Lexer.
     * The temporary buffer contains the null-terminated identifier.
     * The next GetId operation on the lexer will invalidate this
     * temporary buffer.
     */
    int GetId(char const*& x);

    /*
     * Read text until the specified character is hit.
     * X is set as by GetId(char const*&).
     */
    int GetUntil(char, char const*& x);

    /*
     * Read number.
     */
    int GetNumber(int& num);

    /*
     * Read specified number of characters into supplied buffer.
     */
    int GetText(char*, int len);
  protected:
    char*	buf;		/* Contents of entire file */
    int		length;		/* File length */
    int		index;		/* Index of next char in file */
    charArray*	tmp;		/* Temporary buffer */

    /* Last error message */
    static char const* lastError;
};

inline Lexer::StatusType Lexer::Status() {
    if (index == length) {
	return Eof;
    }
    if (index > length) {
	return Error;
    }
    return Valid;
}

inline void Lexer::SetError(char const* msg) {
    lastError = msg;
    index = length+1;
}

inline char const* Lexer::LastError() {
    return lastError;
}

inline int Lexer::Peek(char& c) {
    if (index < length) {
	c = buf[index];
	return 1;
    }
    return 0;
}

inline int Lexer::Next(char& c) {
    if (index < length) {
	c = buf[index];
	index++;
	return 1;
    }
    return 0;
}

inline int Lexer::Advance(char& c) {
    index++;
    if (index < length) {
	c = buf[index];
	return 1;
    }

    /* Undo advance */
    if (index > length) {
	index = length;
    }

    return 0;
}

inline int Lexer::Skip(char c) {
    if ((index < length) && (buf[index] == c)) {
	index++;
	return 1;
    }
    SetError("unexpected character");
    return 0;
}
	
#endif /* _LEXERH */
