xref: /freebsd/contrib/bc/src/lex.c (revision a970610a3af63b3f4df5b69d91c6b4093a00ed8f)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6*a970610aSStefan Eßer  * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7252884aeSStefan Eßer  *
8252884aeSStefan Eßer  * Redistribution and use in source and binary forms, with or without
9252884aeSStefan Eßer  * modification, are permitted provided that the following conditions are met:
10252884aeSStefan Eßer  *
11252884aeSStefan Eßer  * * Redistributions of source code must retain the above copyright notice, this
12252884aeSStefan Eßer  *   list of conditions and the following disclaimer.
13252884aeSStefan Eßer  *
14252884aeSStefan Eßer  * * Redistributions in binary form must reproduce the above copyright notice,
15252884aeSStefan Eßer  *   this list of conditions and the following disclaimer in the documentation
16252884aeSStefan Eßer  *   and/or other materials provided with the distribution.
17252884aeSStefan Eßer  *
18252884aeSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19252884aeSStefan Eßer  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20252884aeSStefan Eßer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21252884aeSStefan Eßer  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22252884aeSStefan Eßer  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23252884aeSStefan Eßer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24252884aeSStefan Eßer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25252884aeSStefan Eßer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26252884aeSStefan Eßer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27252884aeSStefan Eßer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28252884aeSStefan Eßer  * POSSIBILITY OF SUCH DAMAGE.
29252884aeSStefan Eßer  *
30252884aeSStefan Eßer  * *****************************************************************************
31252884aeSStefan Eßer  *
32252884aeSStefan Eßer  * Common code for the lexers.
33252884aeSStefan Eßer  *
34252884aeSStefan Eßer  */
35252884aeSStefan Eßer 
36252884aeSStefan Eßer #include <assert.h>
37252884aeSStefan Eßer #include <ctype.h>
38252884aeSStefan Eßer #include <stdbool.h>
39252884aeSStefan Eßer #include <string.h>
40252884aeSStefan Eßer 
41252884aeSStefan Eßer #include <lex.h>
42252884aeSStefan Eßer #include <vm.h>
43252884aeSStefan Eßer #include <bc.h>
44252884aeSStefan Eßer 
4578bc019dSStefan Eßer void
4678bc019dSStefan Eßer bc_lex_invalidChar(BcLex* l, char c)
4778bc019dSStefan Eßer {
48252884aeSStefan Eßer 	l->t = BC_LEX_INVALID;
4950696a6eSStefan Eßer 	bc_lex_verr(l, BC_ERR_PARSE_CHAR, c);
50252884aeSStefan Eßer }
51252884aeSStefan Eßer 
5278bc019dSStefan Eßer void
5378bc019dSStefan Eßer bc_lex_lineComment(BcLex* l)
5478bc019dSStefan Eßer {
55252884aeSStefan Eßer 	l->t = BC_LEX_WHITESPACE;
5678bc019dSStefan Eßer 	while (l->i < l->len && l->buf[l->i] != '\n')
5778bc019dSStefan Eßer 	{
5878bc019dSStefan Eßer 		l->i += 1;
5978bc019dSStefan Eßer 	}
60252884aeSStefan Eßer }
61252884aeSStefan Eßer 
6278bc019dSStefan Eßer void
6378bc019dSStefan Eßer bc_lex_comment(BcLex* l)
6478bc019dSStefan Eßer {
65252884aeSStefan Eßer 	size_t i, nlines = 0;
6644d4804dSStefan Eßer 	const char* buf;
6744d4804dSStefan Eßer 	bool end = false, got_more;
68252884aeSStefan Eßer 	char c;
69252884aeSStefan Eßer 
70252884aeSStefan Eßer 	l->i += 1;
71252884aeSStefan Eßer 	l->t = BC_LEX_WHITESPACE;
72252884aeSStefan Eßer 
7344d4804dSStefan Eßer 	// This loop is complex because it might need to request more data from
7444d4804dSStefan Eßer 	// stdin if the comment is not ended. This loop is taken until the comment
7544d4804dSStefan Eßer 	// is finished or we have EOF.
7678bc019dSStefan Eßer 	do
7778bc019dSStefan Eßer 	{
7844d4804dSStefan Eßer 		buf = l->buf;
7944d4804dSStefan Eßer 		got_more = false;
8044d4804dSStefan Eßer 
8144d4804dSStefan Eßer 		// If we are in stdin mode, the buffer must be the one used for stdin.
82d101cdd6SStefan Eßer 		assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
8344d4804dSStefan Eßer 
8444d4804dSStefan Eßer 		// Find the end of the comment.
8578bc019dSStefan Eßer 		for (i = l->i; !end; i += !end)
8678bc019dSStefan Eßer 		{
8744d4804dSStefan Eßer 			// While we don't have an asterisk, eat, but increment nlines.
8878bc019dSStefan Eßer 			for (; (c = buf[i]) && c != '*'; ++i)
8978bc019dSStefan Eßer 			{
9078bc019dSStefan Eßer 				nlines += (c == '\n');
9178bc019dSStefan Eßer 			}
92252884aeSStefan Eßer 
9344d4804dSStefan Eßer 			// If this is true, we need to request more data.
9478bc019dSStefan Eßer 			if (BC_ERR(!c || buf[i + 1] == '\0'))
9578bc019dSStefan Eßer 			{
9623210c9fSStefan Eßer 				// Read more, if possible.
97d101cdd6SStefan Eßer 				if (!vm->eof && l->mode != BC_MODE_FILE)
9878bc019dSStefan Eßer 				{
9923210c9fSStefan Eßer 					got_more = bc_lex_readLine(l);
10078bc019dSStefan Eßer 				}
10144d4804dSStefan Eßer 
10244d4804dSStefan Eßer 				break;
103252884aeSStefan Eßer 			}
104252884aeSStefan Eßer 
10544d4804dSStefan Eßer 			// If this turns true, we found the end. Yay!
10644d4804dSStefan Eßer 			end = (buf[i + 1] == '/');
10744d4804dSStefan Eßer 		}
10878bc019dSStefan Eßer 	}
10978bc019dSStefan Eßer 	while (got_more && !end);
11044d4804dSStefan Eßer 
11144d4804dSStefan Eßer 	// If we didn't find the end, barf.
11278bc019dSStefan Eßer 	if (!end)
11378bc019dSStefan Eßer 	{
11444d4804dSStefan Eßer 		l->i = i;
11544d4804dSStefan Eßer 		bc_lex_err(l, BC_ERR_PARSE_COMMENT);
116252884aeSStefan Eßer 	}
117252884aeSStefan Eßer 
118252884aeSStefan Eßer 	l->i = i + 2;
119252884aeSStefan Eßer 	l->line += nlines;
120252884aeSStefan Eßer }
121252884aeSStefan Eßer 
12278bc019dSStefan Eßer void
12378bc019dSStefan Eßer bc_lex_whitespace(BcLex* l)
12478bc019dSStefan Eßer {
125252884aeSStefan Eßer 	char c;
12644d4804dSStefan Eßer 
127252884aeSStefan Eßer 	l->t = BC_LEX_WHITESPACE;
12844d4804dSStefan Eßer 
12944d4804dSStefan Eßer 	// Eat. We don't eat newlines because they can be special.
13078bc019dSStefan Eßer 	for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i])
13178bc019dSStefan Eßer 	{
13278bc019dSStefan Eßer 		continue;
13378bc019dSStefan Eßer 	}
134252884aeSStefan Eßer }
135252884aeSStefan Eßer 
13678bc019dSStefan Eßer void
13778bc019dSStefan Eßer bc_lex_commonTokens(BcLex* l, char c)
13878bc019dSStefan Eßer {
139252884aeSStefan Eßer 	if (!c) l->t = BC_LEX_EOF;
140252884aeSStefan Eßer 	else if (c == '\n') l->t = BC_LEX_NLINE;
141252884aeSStefan Eßer 	else bc_lex_whitespace(l);
142252884aeSStefan Eßer }
143252884aeSStefan Eßer 
14444d4804dSStefan Eßer /**
14544d4804dSStefan Eßer  * Parses a number.
14644d4804dSStefan Eßer  * @param l         The lexer.
14744d4804dSStefan Eßer  * @param start     The start character.
14844d4804dSStefan Eßer  * @param int_only  Whether this function should only look for an integer. This
14944d4804dSStefan Eßer  *                  is used to implement the exponent of scientific notation.
15044d4804dSStefan Eßer  */
15178bc019dSStefan Eßer static size_t
15278bc019dSStefan Eßer bc_lex_num(BcLex* l, char start, bool int_only)
15378bc019dSStefan Eßer {
154252884aeSStefan Eßer 	const char* buf = l->buf + l->i;
155252884aeSStefan Eßer 	size_t i;
156252884aeSStefan Eßer 	char c;
157252884aeSStefan Eßer 	bool last_pt, pt = (start == '.');
158252884aeSStefan Eßer 
15944d4804dSStefan Eßer 	// This loop looks complex. It is not. It is asking if the character is not
16044d4804dSStefan Eßer 	// a nul byte and it if it a valid num character based on what we have found
16144d4804dSStefan Eßer 	// thus far, or whether it is a backslash followed by a newline. I can do
16244d4804dSStefan Eßer 	// i+1 on the buffer because the buffer must have a nul byte.
163252884aeSStefan Eßer 	for (i = 0; (c = buf[i]) && (BC_LEX_NUM_CHAR(c, pt, int_only) ||
16478bc019dSStefan Eßer 	                             (c == '\\' && buf[i + 1] == '\n'));
16578bc019dSStefan Eßer 	     ++i)
166252884aeSStefan Eßer 	{
16744d4804dSStefan Eßer 		// I don't need to test that the next character is a newline because
16844d4804dSStefan Eßer 		// the loop condition above ensures that.
16978bc019dSStefan Eßer 		if (c == '\\')
17078bc019dSStefan Eßer 		{
171252884aeSStefan Eßer 			i += 2;
172252884aeSStefan Eßer 
173252884aeSStefan Eßer 			// Make sure to eat whitespace at the beginning of the line.
17478bc019dSStefan Eßer 			while (isspace(buf[i]) && buf[i] != '\n')
17578bc019dSStefan Eßer 			{
17678bc019dSStefan Eßer 				i += 1;
17778bc019dSStefan Eßer 			}
178252884aeSStefan Eßer 
179252884aeSStefan Eßer 			c = buf[i];
180252884aeSStefan Eßer 
18144d4804dSStefan Eßer 			// If the next character is not a number character, bail.
182252884aeSStefan Eßer 			if (!BC_LEX_NUM_CHAR(c, pt, int_only)) break;
183252884aeSStefan Eßer 		}
184252884aeSStefan Eßer 
18544d4804dSStefan Eßer 		// Did we find the radix point?
186252884aeSStefan Eßer 		last_pt = (c == '.');
18744d4804dSStefan Eßer 
18844d4804dSStefan Eßer 		// If we did, and we already have one, then break because it's not part
18944d4804dSStefan Eßer 		// of this number.
190252884aeSStefan Eßer 		if (pt && last_pt) break;
19144d4804dSStefan Eßer 
19244d4804dSStefan Eßer 		// Set whether we have found a radix point.
193252884aeSStefan Eßer 		pt = pt || last_pt;
194252884aeSStefan Eßer 
195252884aeSStefan Eßer 		bc_vec_push(&l->str, &c);
196252884aeSStefan Eßer 	}
197252884aeSStefan Eßer 
198252884aeSStefan Eßer 	return i;
199252884aeSStefan Eßer }
200252884aeSStefan Eßer 
20178bc019dSStefan Eßer void
20278bc019dSStefan Eßer bc_lex_number(BcLex* l, char start)
20378bc019dSStefan Eßer {
204252884aeSStefan Eßer 	l->t = BC_LEX_NUMBER;
205252884aeSStefan Eßer 
20644d4804dSStefan Eßer 	// Make sure the string is clear.
20710328f8bSStefan Eßer 	bc_vec_popAll(&l->str);
208252884aeSStefan Eßer 	bc_vec_push(&l->str, &start);
209252884aeSStefan Eßer 
21044d4804dSStefan Eßer 	// Parse the number.
211252884aeSStefan Eßer 	l->i += bc_lex_num(l, start, false);
212252884aeSStefan Eßer 
213252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
214252884aeSStefan Eßer 	{
215252884aeSStefan Eßer 		char c = l->buf[l->i];
216252884aeSStefan Eßer 
21744d4804dSStefan Eßer 		// Do we have a number in scientific notation?
21878bc019dSStefan Eßer 		if (c == 'e')
21978bc019dSStefan Eßer 		{
220252884aeSStefan Eßer #if BC_ENABLED
22144d4804dSStefan Eßer 			// Barf for POSIX.
22250696a6eSStefan Eßer 			if (BC_IS_POSIX) bc_lex_err(l, BC_ERR_POSIX_EXP_NUM);
223252884aeSStefan Eßer #endif // BC_ENABLED
224252884aeSStefan Eßer 
22544d4804dSStefan Eßer 			// Push the e.
226252884aeSStefan Eßer 			bc_vec_push(&l->str, &c);
227252884aeSStefan Eßer 			l->i += 1;
228252884aeSStefan Eßer 			c = l->buf[l->i];
229252884aeSStefan Eßer 
23044d4804dSStefan Eßer 			// Check for negative specifically because bc_lex_num() does not.
23178bc019dSStefan Eßer 			if (c == BC_LEX_NEG_CHAR)
23278bc019dSStefan Eßer 			{
233252884aeSStefan Eßer 				bc_vec_push(&l->str, &c);
234252884aeSStefan Eßer 				l->i += 1;
235252884aeSStefan Eßer 				c = l->buf[l->i];
236252884aeSStefan Eßer 			}
237252884aeSStefan Eßer 
23844d4804dSStefan Eßer 			// We must have a number character, so barf if not.
239252884aeSStefan Eßer 			if (BC_ERR(!BC_LEX_NUM_CHAR(c, false, true)))
24078bc019dSStefan Eßer 			{
24150696a6eSStefan Eßer 				bc_lex_verr(l, BC_ERR_PARSE_CHAR, c);
24278bc019dSStefan Eßer 			}
243252884aeSStefan Eßer 
24444d4804dSStefan Eßer 			// Parse the exponent.
245252884aeSStefan Eßer 			l->i += bc_lex_num(l, 0, true);
246252884aeSStefan Eßer 		}
247252884aeSStefan Eßer 	}
248252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
249252884aeSStefan Eßer 
250252884aeSStefan Eßer 	bc_vec_pushByte(&l->str, '\0');
251252884aeSStefan Eßer }
252252884aeSStefan Eßer 
25378bc019dSStefan Eßer void
25478bc019dSStefan Eßer bc_lex_name(BcLex* l)
25578bc019dSStefan Eßer {
256252884aeSStefan Eßer 	size_t i = 0;
257252884aeSStefan Eßer 	const char* buf = l->buf + l->i - 1;
258252884aeSStefan Eßer 	char c = buf[i];
259252884aeSStefan Eßer 
260252884aeSStefan Eßer 	l->t = BC_LEX_NAME;
261252884aeSStefan Eßer 
26244d4804dSStefan Eßer 	// Should be obvious. It's looking for valid characters.
26378bc019dSStefan Eßer 	while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_')
26478bc019dSStefan Eßer 	{
26578bc019dSStefan Eßer 		c = buf[++i];
26678bc019dSStefan Eßer 	}
267252884aeSStefan Eßer 
26844d4804dSStefan Eßer 	// Set the string to the identifier.
269252884aeSStefan Eßer 	bc_vec_string(&l->str, i, buf);
270252884aeSStefan Eßer 
271252884aeSStefan Eßer 	// Increment the index. We minus 1 because it has already been incremented.
272252884aeSStefan Eßer 	l->i += i - 1;
273252884aeSStefan Eßer }
274252884aeSStefan Eßer 
27578bc019dSStefan Eßer void
27678bc019dSStefan Eßer bc_lex_init(BcLex* l)
27778bc019dSStefan Eßer {
278252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
279252884aeSStefan Eßer 	assert(l != NULL);
28044d4804dSStefan Eßer 	bc_vec_init(&l->str, sizeof(char), BC_DTOR_NONE);
281252884aeSStefan Eßer }
282252884aeSStefan Eßer 
28378bc019dSStefan Eßer void
28478bc019dSStefan Eßer bc_lex_free(BcLex* l)
28578bc019dSStefan Eßer {
286252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
287252884aeSStefan Eßer 	assert(l != NULL);
288252884aeSStefan Eßer 	bc_vec_free(&l->str);
289252884aeSStefan Eßer }
290252884aeSStefan Eßer 
29178bc019dSStefan Eßer void
29278bc019dSStefan Eßer bc_lex_file(BcLex* l, const char* file)
29378bc019dSStefan Eßer {
294252884aeSStefan Eßer 	assert(l != NULL && file != NULL);
295252884aeSStefan Eßer 	l->line = 1;
296d101cdd6SStefan Eßer 	vm->file = file;
297252884aeSStefan Eßer }
298252884aeSStefan Eßer 
29978bc019dSStefan Eßer void
30078bc019dSStefan Eßer bc_lex_next(BcLex* l)
30178bc019dSStefan Eßer {
30210041e99SStefan Eßer 	BC_SIG_ASSERT_LOCKED;
30310041e99SStefan Eßer 
304252884aeSStefan Eßer 	assert(l != NULL);
305252884aeSStefan Eßer 
306252884aeSStefan Eßer 	l->last = l->t;
30744d4804dSStefan Eßer 
30844d4804dSStefan Eßer 	// If this wasn't here, the line number would be off.
309252884aeSStefan Eßer 	l->line += (l->i != 0 && l->buf[l->i - 1] == '\n');
310252884aeSStefan Eßer 
31144d4804dSStefan Eßer 	// If the last token was EOF, someone called this one too many times.
31250696a6eSStefan Eßer 	if (BC_ERR(l->last == BC_LEX_EOF)) bc_lex_err(l, BC_ERR_PARSE_EOF);
313252884aeSStefan Eßer 
314252884aeSStefan Eßer 	l->t = BC_LEX_EOF;
315252884aeSStefan Eßer 
31644d4804dSStefan Eßer 	// We are done if this is true.
317252884aeSStefan Eßer 	if (l->i == l->len) return;
318252884aeSStefan Eßer 
319252884aeSStefan Eßer 	// Loop until failure or we don't have whitespace. This
320252884aeSStefan Eßer 	// is so the parser doesn't get inundated with whitespace.
32178bc019dSStefan Eßer 	do
32278bc019dSStefan Eßer 	{
323d101cdd6SStefan Eßer 		vm->next(l);
32478bc019dSStefan Eßer 	}
32578bc019dSStefan Eßer 	while (l->t == BC_LEX_WHITESPACE);
326252884aeSStefan Eßer }
327252884aeSStefan Eßer 
32844d4804dSStefan Eßer /**
32944d4804dSStefan Eßer  * Updates the buffer and len so that they are not invalidated when the stdin
33044d4804dSStefan Eßer  * buffer grows.
33144d4804dSStefan Eßer  * @param l     The lexer.
33244d4804dSStefan Eßer  * @param text  The text.
33344d4804dSStefan Eßer  * @param len   The length of the text.
33444d4804dSStefan Eßer  */
33578bc019dSStefan Eßer static void
33678bc019dSStefan Eßer bc_lex_fixText(BcLex* l, const char* text, size_t len)
33778bc019dSStefan Eßer {
338252884aeSStefan Eßer 	l->buf = text;
33944d4804dSStefan Eßer 	l->len = len;
34044d4804dSStefan Eßer }
34144d4804dSStefan Eßer 
34278bc019dSStefan Eßer bool
34378bc019dSStefan Eßer bc_lex_readLine(BcLex* l)
34478bc019dSStefan Eßer {
34510041e99SStefan Eßer 	bool good;
34610041e99SStefan Eßer 
34710041e99SStefan Eßer 	// These are reversed because they should be already locked, but
34810041e99SStefan Eßer 	// bc_vm_readLine() needs them to be unlocked.
34910041e99SStefan Eßer 	BC_SIG_UNLOCK;
35010041e99SStefan Eßer 
35123210c9fSStefan Eßer 	// Make sure we read from the appropriate place.
352d101cdd6SStefan Eßer 	switch (l->mode)
35378bc019dSStefan Eßer 	{
354d101cdd6SStefan Eßer 		case BC_MODE_EXPRS:
355d101cdd6SStefan Eßer 		{
35623210c9fSStefan Eßer 			good = bc_vm_readBuf(false);
357d101cdd6SStefan Eßer 			break;
358d101cdd6SStefan Eßer 		}
359d101cdd6SStefan Eßer 
360d101cdd6SStefan Eßer 		case BC_MODE_FILE:
361d101cdd6SStefan Eßer 		{
362d101cdd6SStefan Eßer 			good = false;
363d101cdd6SStefan Eßer 			break;
364d101cdd6SStefan Eßer 		}
365d101cdd6SStefan Eßer 
366d101cdd6SStefan Eßer 		case BC_MODE_STDIN:
367d101cdd6SStefan Eßer 		{
368d101cdd6SStefan Eßer 			good = bc_vm_readLine(false);
369d101cdd6SStefan Eßer 			break;
370d101cdd6SStefan Eßer 		}
371d101cdd6SStefan Eßer 
372d101cdd6SStefan Eßer #ifdef __GNUC__
373d101cdd6SStefan Eßer #ifndef __clang__
374d101cdd6SStefan Eßer 		default:
375d101cdd6SStefan Eßer 		{
376d101cdd6SStefan Eßer 			// We should never get here.
377d101cdd6SStefan Eßer 			abort();
378d101cdd6SStefan Eßer 		}
379d101cdd6SStefan Eßer #endif // __clang__
380d101cdd6SStefan Eßer #endif // __GNUC__
38123210c9fSStefan Eßer 	}
38210041e99SStefan Eßer 
38310041e99SStefan Eßer 	BC_SIG_LOCK;
38444d4804dSStefan Eßer 
385d101cdd6SStefan Eßer 	bc_lex_fixText(l, vm->buffer.v, vm->buffer.len - 1);
38644d4804dSStefan Eßer 
38744d4804dSStefan Eßer 	return good;
38844d4804dSStefan Eßer }
38944d4804dSStefan Eßer 
39078bc019dSStefan Eßer void
391d101cdd6SStefan Eßer bc_lex_text(BcLex* l, const char* text, BcMode mode)
39278bc019dSStefan Eßer {
39310041e99SStefan Eßer 	BC_SIG_ASSERT_LOCKED;
39410041e99SStefan Eßer 
39544d4804dSStefan Eßer 	assert(l != NULL && text != NULL);
39610041e99SStefan Eßer 
39744d4804dSStefan Eßer 	bc_lex_fixText(l, text, strlen(text));
398252884aeSStefan Eßer 	l->i = 0;
399252884aeSStefan Eßer 	l->t = l->last = BC_LEX_INVALID;
400d101cdd6SStefan Eßer 	l->mode = mode;
40110041e99SStefan Eßer 
402252884aeSStefan Eßer 	bc_lex_next(l);
403252884aeSStefan Eßer }
404