summaryrefslogtreecommitdiffstats
path: root/lib/antlr/antlr/InputBuffer.hpp
blob: b979ef8c37c2521aec84c22acb2ed4cbb8e685a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#ifndef INC_InputBuffer_hpp__
#define INC_InputBuffer_hpp__

/* ANTLR Translator Generator
 * Project led by Terence Parr at http://www.jGuru.com
 * Software rights: http://www.antlr.org/license.html
 *
 * $Id$
 */

#include <antlr/config.hpp>
#include <antlr/CircularQueue.hpp>
#include <string>

#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
namespace antlr {
#endif

/** A Stream of characters fed to the lexer from a InputStream that can
 * be rewound via mark()/rewind() methods.
 * <p>
 * A dynamic array is used to buffer up all the input characters.  Normally,
 * "k" characters are stored in the buffer.  More characters may be stored during
 * guess mode (testing syntactic predicate), or when LT(i>k) is referenced.
 * Consumption of characters is deferred.  In other words, reading the next
 * character is not done by conume(), but deferred until needed by LA or LT.
 * <p>
 *
 * @see antlr.CharQueue
 */
class ANTLR_API InputBuffer {
public:
	/** Create a character buffer */
	InputBuffer()
	: nMarkers(0)
	, markerOffset(0)
	, numToConsume(0)
	{
	}

	virtual ~InputBuffer()
	{
	}

	/// Reset the input buffer to empty state
	virtual inline void reset( void )
	{
		nMarkers = 0;
		markerOffset = 0;
		numToConsume = 0;
		queue.clear();
	}

	/** This method updates the state of the input buffer so that
	 * the text matched since the most recent mark() is no longer
	 * held by the buffer.  So, you either do a mark/rewind for
	 * failed predicate or mark/commit to keep on parsing without
	 * rewinding the input.
	 */
	inline void commit( void )
	{
		nMarkers--;
	}

	/** Mark another character for deferred consumption */
	virtual inline void consume()
	{
		numToConsume++;
	}

	/** Ensure that the character buffer is sufficiently full */
	virtual void fill(unsigned int amount);

	/** Override this in subclasses to get the next character */
	virtual int getChar()=0;

	/** Get a lookahead character */
	virtual inline int LA(unsigned int i)
	{
		fill(i);
		return queue.elementAt(markerOffset + i - 1);
	}

	/** Return an integer marker that can be used to rewind the buffer to
	 * its current state.
	 */
	virtual unsigned int mark();
	/// Are there any marks active in the InputBuffer
	virtual inline bool isMarked() const
	{
		return (nMarkers != 0);
	}
	/** Rewind the character buffer to a marker.
	 * @param mark Marker returned previously from mark()
	 */
	virtual void rewind(unsigned int mark);

	/** Get the number of non-consumed characters
	 */
	virtual unsigned int entries() const;

	ANTLR_USE_NAMESPACE(std)string getLAChars() const;

	ANTLR_USE_NAMESPACE(std)string getMarkedChars() const;

protected:
	// char source
	// leave to subclasses

	// Number of active markers
	unsigned int nMarkers; // = 0;

	// Additional offset used when markers are active
	unsigned int markerOffset; // = 0;

	// Number of calls to consume() since last LA() or LT() call
	unsigned int numToConsume; // = 0;

	// Circular queue
	CircularQueue<int> queue;

	/** Sync up deferred consumption */
	void syncConsume();

private:
	InputBuffer(const InputBuffer& other);
	InputBuffer& operator=(const InputBuffer& other);
};

/** Sync up deferred consumption */
inline void InputBuffer::syncConsume() {
	if (numToConsume > 0)
	{
		if (nMarkers > 0)
			markerOffset += numToConsume;
		else
			queue.removeItems( numToConsume );
		numToConsume = 0;
	}
}

#ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
}
#endif

#endif //INC_InputBuffer_hpp__