Frobby 0.9.5
Scanner.cpp
Go to the documentation of this file.
1/* Frobby: Software for monomial ideal computations.
2 Copyright (C) 2007 Bjarke Hammersholt Roune (www.broune.com)
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see http://www.gnu.org/licenses/.
16*/
17#include "stdinc.h"
18#include "Scanner.h"
19
20#include "VarNames.h"
21#include "IOHandler.h"
22#include "error.h"
23#include "FrobbyStringStream.h"
24#include <limits>
25
26static const size_t BufferSize = 10024;
27
29 _in(in),
30 _lineNumber(1),
31 _char(' '),
32 _tmpString(0),
33 _tmpStringCapacity(16),
34 _formatName(formatName),
35 _buffer(BufferSize),
36 _bufferPos(_buffer.end()) {
39 _tmpString = new char[16];
40}
41
43 return ::createIOHandler(getFormat());
44}
45
46void Scanner::expect(const char* str) {
47 ASSERT(str != 0);
48
49 eatWhite();
50
51 const char* it = str;
52 while (*it != '\0') {
53 int character = getChar();
54 if (*it == character) {
55 ++it;
56 continue;
57 }
58
59 // Read the rest of what is there to improve error message.
60 // TODO: read at least one char in total even if not alnum.
62 if (character == EOF && it == str)
63 got << "no more input";
64 else {
65 got << '\"' << string(str, it);
66 if (isalnum(character))
68 while (isalnum(peek()))
70 got << '\"';
71 }
72
74 }
75}
76
78 // TODO: get this moved into the null format itself.
79 if (_formatName == "null")
80 return;
81
82 eatWhite();
83 if (getChar() != EOF)
84 reportErrorUnexpectedToken("no more input", "");
85}
86
87void Scanner::errorExpectTwo(char a, char b, int got) {
88 ASSERT(a != got && b != got);
90 err << a << " or " << b;
92}
93
100
102 eatWhite();
103
105
106 if (peek() == '-' || peek() == '+')
107 _tmpString[0] = static_cast<char>(getChar());
108 else
109 _tmpString[0] = '+';
110
111 size_t size = 1;
112
113 while (isdigit(peek())) {
114 _tmpString[size] = static_cast<char>(getChar());
115 ++size;
116 if (size == _tmpStringCapacity)
118 }
119 _tmpString[size] = '\0';
120
121 if (size == 1)
122 reportErrorUnexpectedToken("an integer", "");
123
124 return size;
125}
126
128 eatWhite();
129 if (peek() == '-' || peek() == '+')
130 reportErrorUnexpectedToken("integer without preceding sign", peek());
131 // todo: remove code duplication with readIntegerString.
132
134
135 size_t size = 0;
136 while (isdigit(peek())) {
137 _tmpString[size] = static_cast<char>(getChar());
138 ++size;
139 if (size == _tmpStringCapacity)
141 }
142 _tmpString[size] = '\0';
143
144 if (size == 0)
145 reportErrorUnexpectedToken("an integer", "");
146
147 return size;
148}
149
151 // This code has a fast path for small integers and a slower path
152 // for longer integers. The largest number representable in 32 bits
153 // has 10 digits in base 10 and 1 char for the sign. If the number
154 // we are reading has less than 10 digits, then we calculate it
155 // directly without consulting GMP, which is faster.
156
157 if (size < 10) {
158 signed long l = 0;
159 for (size_t i = 1; i < size; ++i)
160 l = 10 * l + (_tmpString[i] - '0');
161 if (_tmpString[0] == '-')
162 l = -l;
163 integer = l;
164 } else {
165 // For whatever reason mp_set_str does not support a + as the
166 // first character.
167 mpz_set_str(integer.get_mpz_t(), _tmpString + (_tmpString[0] != '-'), 10);
168 }
169}
170
172 // Fast path for common case of reading a zero.
173 if (peek() == '0') {
174 getChar();
175 if (!isdigit(peek())) {
176 integer = 0;
177 return;
178 }
179 }
180
181 size_t size = readIntegerString();
182 if (_tmpString[0] == '-')
183 integer = 0;
184 else
185 parseInteger(integer, size);
186}
187
189 // Fast path for common case of reading a zero.
190 if (peek() == '0') {
191 getChar();
192 if (!isdigit(peek())) {
193 integer = '0';
194 return;
195 }
196 }
197
199 if (_tmpString[0] == '-')
200 integer = '0';
201 else
202 integer = _tmpString + 1;
203}
204
205void Scanner::readSizeT(size_t& size) {
207
208 // Deal with different possibilities for how large size_t is.
209 if (sizeof(size_t) == sizeof(unsigned int)) {
210 if (!_integer.fits_uint_p()) {
212 errorMsg << "expected non-negative integer of size at most "
213 << numeric_limits<unsigned int>::max()
214 << " but got " << _integer << '.';
216 }
217 size = (unsigned int)_integer.get_ui();
218 } else if (sizeof(size_t) == sizeof(unsigned long)) {
219 if (!_integer.fits_ulong_p()) {
221 errorMsg << "expected non-negative integer of size at most "
222 << numeric_limits<unsigned long>::max()
223 << " but got " << _integer << '.';
225 }
226 size = _integer.get_ui(); // returns an unsigned long despite the name.
227 } else {
229 errorMsg <<
230 "Frobby does not work on this machine due to an "
231 "unexpected technical issue.\n"
232 "Please contact the developers of Frobby about this.\n"
233 "\n"
234 "Details that will be useful to the developers:\n"
235 " error location: Scanner::readSizeT\n"
236 " sizeof(size_t) = " << sizeof(size_t) << "\n"
237 " sizeof(unsigned int) = " << sizeof(unsigned int) << "\n"
238 " sizeof(unsigned long) = " << sizeof(unsigned long) << "\n";
240 }
241}
242
245 size_t newCapacity = _tmpStringCapacity * 2;
246 char* str = new char[newCapacity];
247 for (size_t i = 0; i < _tmpStringCapacity; ++i)
248 str[i] = _tmpString[i];
249 delete[] _tmpString;
250
251 _tmpString = str;
253}
254
256 eatWhite();
257 if (!isalpha(peek()))
259
261
262 size_t size = 0;
263 while (isalnum(peek()) || peek() == '_') {
264 _tmpString[size] = static_cast<char>(getChar());
265 ++size;
266 if (size == _tmpStringCapacity)
268 }
269 _tmpString[size] = '\0';
270
271 return _tmpString;
272}
273
275 reportErrorUnexpectedToken("an identifier", "");
276}
277
280 errorMsg << "Unknown variable \"" << name << "\". Maybe you forgot a *.";
282}
283
285(const string& expected, int got) {
287 if (got == EOF)
288 gotDescription << "no more input";
289 else
290 gotDescription << '\"' << static_cast<char>(got)<< '\"';
292}
293
295(const string& expected, const string& got) {
297 errorMsg << "Expected " << expected;
298 if (got != "")
299 errorMsg << ", but got " << got;
300 errorMsg << '.';
302}
303
305 if (_buffer.size() < _buffer.capacity() && (feof(_in) || ferror(_in)))
306 return EOF;
307 _buffer.resize(_buffer.capacity());
308 size_t read = fread(&_buffer[0], 1, _buffer.capacity(), _in);
309 _buffer.resize(read);
310 _bufferPos = _buffer.begin();
311 if (read == 0)
312 return EOF;
313 char c = *_bufferPos;
314 ++_bufferPos;
315 return c;
316}
string getFormatNameIndicatingToGuessTheInputFormat()
Using the returned string in place of an (input) format name indicates to guess the format based on w...
string autoDetectFormat(Scanner &in)
Return the format of what in is reading based on the first non-whitespace character.
void nameFactoryRegister(NameFactory< AbstractProduct > &factory)
Registers the string returned by ConcreteProduct::getStaticName() to a function that default-construc...
static const size_t BufferSize
Definition Scanner.cpp:26
A replacement for stringstream.
auto_ptr< IOHandler > createIOHandler() const
Definition Scanner.cpp:42
mpz_class _integer
Definition Scanner.h:175
int peek()
Returns the next character or EOF.
Definition Scanner.h:148
size_t readIntegerString()
Returns the size of the string.
Definition Scanner.cpp:101
void growTmpString()
Definition Scanner.cpp:243
char * _tmpString
Definition Scanner.h:180
size_t _tmpStringCapacity
Definition Scanner.h:181
void parseInteger(mpz_class &integer, size_t size)
Definition Scanner.cpp:150
string _formatName
Definition Scanner.h:183
Scanner(const string &formatName, FILE *in)
Construct a Scanner object.
Definition Scanner.cpp:28
void reportErrorUnexpectedToken(const string &expected, int got)
Definition Scanner.cpp:285
FILE * _in
Definition Scanner.h:176
void eatWhite()
Reads past any whitespace, where whitespace is defined by the standard function isspace().
Definition Scanner.h:267
vector< char >::iterator _bufferPos
Definition Scanner.h:186
vector< char > _buffer
Definition Scanner.h:185
void errorReadIdentifier()
Definition Scanner.cpp:274
void expectEOF()
Require that there is no more input.
Definition Scanner.cpp:77
void readIntegerAndNegativeAsZero(mpz_class &integer)
Read an integer and set it to zero if it is negative.
Definition Scanner.cpp:171
void expect(char expected)
Require the next character to be equal to expected.
Definition Scanner.h:231
const char * readIdentifier()
The returned string is only valid until the next method on this object gets called.
Definition Scanner.cpp:255
void errorExpectTwo(char a, char b, int got)
Definition Scanner.cpp:87
void readSizeT(size_t &size)
Reads a size_t, where the representable range of that type determines when the number is too big.
Definition Scanner.cpp:205
int readBuffer()
Definition Scanner.cpp:304
const string & getFormat() const
Definition Scanner.h:61
void readInteger(mpz_class &integer)
Read an arbitrary-precision integer.
Definition Scanner.h:238
void errorExpectOne(char expected, int got)
Definition Scanner.cpp:94
void setFormat(const string &format)
Definition Scanner.h:62
void errorReadVariable(const char *name)
Definition Scanner.cpp:278
int getChar()
Definition Scanner.h:272
size_t readIntegerStringNoSign()
Returns the size of the string.
Definition Scanner.cpp:127
void reportInternalError(const string &errorMsg)
Definition error.cpp:29
void reportSyntaxError(const Scanner &scanner, const string &errorMsg)
Definition error.cpp:44
#define ASSERT(X)
Definition stdinc.h:86