xref: /aosp_15_r20/external/bc/src/lex.c (revision 5a6e848804d15c18a0125914844ee4eb0bda4fcf)
1*5a6e8488SAndroid Build Coastguard Worker /*
2*5a6e8488SAndroid Build Coastguard Worker  * *****************************************************************************
3*5a6e8488SAndroid Build Coastguard Worker  *
4*5a6e8488SAndroid Build Coastguard Worker  * SPDX-License-Identifier: BSD-2-Clause
5*5a6e8488SAndroid Build Coastguard Worker  *
6*5a6e8488SAndroid Build Coastguard Worker  * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7*5a6e8488SAndroid Build Coastguard Worker  *
8*5a6e8488SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
9*5a6e8488SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions are met:
10*5a6e8488SAndroid Build Coastguard Worker  *
11*5a6e8488SAndroid Build Coastguard Worker  * * Redistributions of source code must retain the above copyright notice, this
12*5a6e8488SAndroid Build Coastguard Worker  *   list of conditions and the following disclaimer.
13*5a6e8488SAndroid Build Coastguard Worker  *
14*5a6e8488SAndroid Build Coastguard Worker  * * Redistributions in binary form must reproduce the above copyright notice,
15*5a6e8488SAndroid Build Coastguard Worker  *   this list of conditions and the following disclaimer in the documentation
16*5a6e8488SAndroid Build Coastguard Worker  *   and/or other materials provided with the distribution.
17*5a6e8488SAndroid Build Coastguard Worker  *
18*5a6e8488SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*5a6e8488SAndroid Build Coastguard Worker  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*5a6e8488SAndroid Build Coastguard Worker  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*5a6e8488SAndroid Build Coastguard Worker  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*5a6e8488SAndroid Build Coastguard Worker  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*5a6e8488SAndroid Build Coastguard Worker  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*5a6e8488SAndroid Build Coastguard Worker  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*5a6e8488SAndroid Build Coastguard Worker  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*5a6e8488SAndroid Build Coastguard Worker  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*5a6e8488SAndroid Build Coastguard Worker  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*5a6e8488SAndroid Build Coastguard Worker  * POSSIBILITY OF SUCH DAMAGE.
29*5a6e8488SAndroid Build Coastguard Worker  *
30*5a6e8488SAndroid Build Coastguard Worker  * *****************************************************************************
31*5a6e8488SAndroid Build Coastguard Worker  *
32*5a6e8488SAndroid Build Coastguard Worker  * Common code for the lexers.
33*5a6e8488SAndroid Build Coastguard Worker  *
34*5a6e8488SAndroid Build Coastguard Worker  */
35*5a6e8488SAndroid Build Coastguard Worker 
36*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
37*5a6e8488SAndroid Build Coastguard Worker #include <ctype.h>
38*5a6e8488SAndroid Build Coastguard Worker #include <stdbool.h>
39*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
40*5a6e8488SAndroid Build Coastguard Worker 
41*5a6e8488SAndroid Build Coastguard Worker #include <lex.h>
42*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
43*5a6e8488SAndroid Build Coastguard Worker #include <bc.h>
44*5a6e8488SAndroid Build Coastguard Worker 
45*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_invalidChar(BcLex * l,char c)46*5a6e8488SAndroid Build Coastguard Worker bc_lex_invalidChar(BcLex* l, char c)
47*5a6e8488SAndroid Build Coastguard Worker {
48*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_INVALID;
49*5a6e8488SAndroid Build Coastguard Worker 	bc_lex_verr(l, BC_ERR_PARSE_CHAR, c);
50*5a6e8488SAndroid Build Coastguard Worker }
51*5a6e8488SAndroid Build Coastguard Worker 
52*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_lineComment(BcLex * l)53*5a6e8488SAndroid Build Coastguard Worker bc_lex_lineComment(BcLex* l)
54*5a6e8488SAndroid Build Coastguard Worker {
55*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_WHITESPACE;
56*5a6e8488SAndroid Build Coastguard Worker 	while (l->i < l->len && l->buf[l->i] != '\n')
57*5a6e8488SAndroid Build Coastguard Worker 	{
58*5a6e8488SAndroid Build Coastguard Worker 		l->i += 1;
59*5a6e8488SAndroid Build Coastguard Worker 	}
60*5a6e8488SAndroid Build Coastguard Worker }
61*5a6e8488SAndroid Build Coastguard Worker 
62*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_comment(BcLex * l)63*5a6e8488SAndroid Build Coastguard Worker bc_lex_comment(BcLex* l)
64*5a6e8488SAndroid Build Coastguard Worker {
65*5a6e8488SAndroid Build Coastguard Worker 	size_t i, nlines = 0;
66*5a6e8488SAndroid Build Coastguard Worker 	const char* buf;
67*5a6e8488SAndroid Build Coastguard Worker 	bool end = false, got_more;
68*5a6e8488SAndroid Build Coastguard Worker 	char c;
69*5a6e8488SAndroid Build Coastguard Worker 
70*5a6e8488SAndroid Build Coastguard Worker 	l->i += 1;
71*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_WHITESPACE;
72*5a6e8488SAndroid Build Coastguard Worker 
73*5a6e8488SAndroid Build Coastguard Worker 	// This loop is complex because it might need to request more data from
74*5a6e8488SAndroid Build Coastguard Worker 	// stdin if the comment is not ended. This loop is taken until the comment
75*5a6e8488SAndroid Build Coastguard Worker 	// is finished or we have EOF.
76*5a6e8488SAndroid Build Coastguard Worker 	do
77*5a6e8488SAndroid Build Coastguard Worker 	{
78*5a6e8488SAndroid Build Coastguard Worker 		buf = l->buf;
79*5a6e8488SAndroid Build Coastguard Worker 		got_more = false;
80*5a6e8488SAndroid Build Coastguard Worker 
81*5a6e8488SAndroid Build Coastguard Worker 		// If we are in stdin mode, the buffer must be the one used for stdin.
82*5a6e8488SAndroid Build Coastguard Worker #if !BC_ENABLE_OSSFUZZ
83*5a6e8488SAndroid Build Coastguard Worker 		assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
84*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_ENABLE_OSSFUZZ
85*5a6e8488SAndroid Build Coastguard Worker 
86*5a6e8488SAndroid Build Coastguard Worker 		// Find the end of the comment.
87*5a6e8488SAndroid Build Coastguard Worker 		for (i = l->i; !end; i += !end)
88*5a6e8488SAndroid Build Coastguard Worker 		{
89*5a6e8488SAndroid Build Coastguard Worker 			// While we don't have an asterisk, eat, but increment nlines.
90*5a6e8488SAndroid Build Coastguard Worker 			for (; (c = buf[i]) && c != '*'; ++i)
91*5a6e8488SAndroid Build Coastguard Worker 			{
92*5a6e8488SAndroid Build Coastguard Worker 				nlines += (c == '\n');
93*5a6e8488SAndroid Build Coastguard Worker 			}
94*5a6e8488SAndroid Build Coastguard Worker 
95*5a6e8488SAndroid Build Coastguard Worker 			// If this is true, we need to request more data.
96*5a6e8488SAndroid Build Coastguard Worker 			if (BC_ERR(!c || buf[i + 1] == '\0'))
97*5a6e8488SAndroid Build Coastguard Worker 			{
98*5a6e8488SAndroid Build Coastguard Worker #if !BC_ENABLE_OSSFUZZ
99*5a6e8488SAndroid Build Coastguard Worker 				// Read more, if possible.
100*5a6e8488SAndroid Build Coastguard Worker 				if (!vm->eof && l->mode != BC_MODE_FILE)
101*5a6e8488SAndroid Build Coastguard Worker 				{
102*5a6e8488SAndroid Build Coastguard Worker 					got_more = bc_lex_readLine(l);
103*5a6e8488SAndroid Build Coastguard Worker 				}
104*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_ENABLE_OSSFUZZ
105*5a6e8488SAndroid Build Coastguard Worker 
106*5a6e8488SAndroid Build Coastguard Worker 				break;
107*5a6e8488SAndroid Build Coastguard Worker 			}
108*5a6e8488SAndroid Build Coastguard Worker 
109*5a6e8488SAndroid Build Coastguard Worker 			// If this turns true, we found the end. Yay!
110*5a6e8488SAndroid Build Coastguard Worker 			end = (buf[i + 1] == '/');
111*5a6e8488SAndroid Build Coastguard Worker 		}
112*5a6e8488SAndroid Build Coastguard Worker 	}
113*5a6e8488SAndroid Build Coastguard Worker 	while (got_more && !end);
114*5a6e8488SAndroid Build Coastguard Worker 
115*5a6e8488SAndroid Build Coastguard Worker 	// If we didn't find the end, barf.
116*5a6e8488SAndroid Build Coastguard Worker 	if (!end)
117*5a6e8488SAndroid Build Coastguard Worker 	{
118*5a6e8488SAndroid Build Coastguard Worker 		l->i = i;
119*5a6e8488SAndroid Build Coastguard Worker 		bc_lex_err(l, BC_ERR_PARSE_COMMENT);
120*5a6e8488SAndroid Build Coastguard Worker 	}
121*5a6e8488SAndroid Build Coastguard Worker 
122*5a6e8488SAndroid Build Coastguard Worker 	l->i = i + 2;
123*5a6e8488SAndroid Build Coastguard Worker 	l->line += nlines;
124*5a6e8488SAndroid Build Coastguard Worker }
125*5a6e8488SAndroid Build Coastguard Worker 
126*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_whitespace(BcLex * l)127*5a6e8488SAndroid Build Coastguard Worker bc_lex_whitespace(BcLex* l)
128*5a6e8488SAndroid Build Coastguard Worker {
129*5a6e8488SAndroid Build Coastguard Worker 	char c;
130*5a6e8488SAndroid Build Coastguard Worker 
131*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_WHITESPACE;
132*5a6e8488SAndroid Build Coastguard Worker 
133*5a6e8488SAndroid Build Coastguard Worker 	// Eat. We don't eat newlines because they can be special.
134*5a6e8488SAndroid Build Coastguard Worker 	for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i])
135*5a6e8488SAndroid Build Coastguard Worker 	{
136*5a6e8488SAndroid Build Coastguard Worker 		continue;
137*5a6e8488SAndroid Build Coastguard Worker 	}
138*5a6e8488SAndroid Build Coastguard Worker }
139*5a6e8488SAndroid Build Coastguard Worker 
140*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_commonTokens(BcLex * l,char c)141*5a6e8488SAndroid Build Coastguard Worker bc_lex_commonTokens(BcLex* l, char c)
142*5a6e8488SAndroid Build Coastguard Worker {
143*5a6e8488SAndroid Build Coastguard Worker 	if (!c) l->t = BC_LEX_EOF;
144*5a6e8488SAndroid Build Coastguard Worker 	else if (c == '\n') l->t = BC_LEX_NLINE;
145*5a6e8488SAndroid Build Coastguard Worker 	else bc_lex_whitespace(l);
146*5a6e8488SAndroid Build Coastguard Worker }
147*5a6e8488SAndroid Build Coastguard Worker 
148*5a6e8488SAndroid Build Coastguard Worker /**
149*5a6e8488SAndroid Build Coastguard Worker  * Parses a number.
150*5a6e8488SAndroid Build Coastguard Worker  * @param l         The lexer.
151*5a6e8488SAndroid Build Coastguard Worker  * @param start     The start character.
152*5a6e8488SAndroid Build Coastguard Worker  * @param int_only  Whether this function should only look for an integer. This
153*5a6e8488SAndroid Build Coastguard Worker  *                  is used to implement the exponent of scientific notation.
154*5a6e8488SAndroid Build Coastguard Worker  */
155*5a6e8488SAndroid Build Coastguard Worker static size_t
bc_lex_num(BcLex * l,char start,bool int_only)156*5a6e8488SAndroid Build Coastguard Worker bc_lex_num(BcLex* l, char start, bool int_only)
157*5a6e8488SAndroid Build Coastguard Worker {
158*5a6e8488SAndroid Build Coastguard Worker 	const char* buf = l->buf + l->i;
159*5a6e8488SAndroid Build Coastguard Worker 	size_t i;
160*5a6e8488SAndroid Build Coastguard Worker 	char c;
161*5a6e8488SAndroid Build Coastguard Worker 	bool last_pt, pt = (start == '.');
162*5a6e8488SAndroid Build Coastguard Worker 
163*5a6e8488SAndroid Build Coastguard Worker 	// This loop looks complex. It is not. It is asking if the character is not
164*5a6e8488SAndroid Build Coastguard Worker 	// a nul byte and it if it a valid num character based on what we have found
165*5a6e8488SAndroid Build Coastguard Worker 	// thus far, or whether it is a backslash followed by a newline. I can do
166*5a6e8488SAndroid Build Coastguard Worker 	// i+1 on the buffer because the buffer must have a nul byte.
167*5a6e8488SAndroid Build Coastguard Worker 	for (i = 0; (c = buf[i]) && (BC_LEX_NUM_CHAR(c, pt, int_only) ||
168*5a6e8488SAndroid Build Coastguard Worker 	                             (c == '\\' && buf[i + 1] == '\n'));
169*5a6e8488SAndroid Build Coastguard Worker 	     ++i)
170*5a6e8488SAndroid Build Coastguard Worker 	{
171*5a6e8488SAndroid Build Coastguard Worker 		// I don't need to test that the next character is a newline because
172*5a6e8488SAndroid Build Coastguard Worker 		// the loop condition above ensures that.
173*5a6e8488SAndroid Build Coastguard Worker 		if (c == '\\')
174*5a6e8488SAndroid Build Coastguard Worker 		{
175*5a6e8488SAndroid Build Coastguard Worker 			i += 2;
176*5a6e8488SAndroid Build Coastguard Worker 
177*5a6e8488SAndroid Build Coastguard Worker 			// Make sure to eat whitespace at the beginning of the line.
178*5a6e8488SAndroid Build Coastguard Worker 			while (isspace(buf[i]) && buf[i] != '\n')
179*5a6e8488SAndroid Build Coastguard Worker 			{
180*5a6e8488SAndroid Build Coastguard Worker 				i += 1;
181*5a6e8488SAndroid Build Coastguard Worker 			}
182*5a6e8488SAndroid Build Coastguard Worker 
183*5a6e8488SAndroid Build Coastguard Worker 			c = buf[i];
184*5a6e8488SAndroid Build Coastguard Worker 
185*5a6e8488SAndroid Build Coastguard Worker 			// If the next character is not a number character, bail.
186*5a6e8488SAndroid Build Coastguard Worker 			if (!BC_LEX_NUM_CHAR(c, pt, int_only)) break;
187*5a6e8488SAndroid Build Coastguard Worker 		}
188*5a6e8488SAndroid Build Coastguard Worker 
189*5a6e8488SAndroid Build Coastguard Worker 		// Did we find the radix point?
190*5a6e8488SAndroid Build Coastguard Worker 		last_pt = (c == '.');
191*5a6e8488SAndroid Build Coastguard Worker 
192*5a6e8488SAndroid Build Coastguard Worker 		// If we did, and we already have one, then break because it's not part
193*5a6e8488SAndroid Build Coastguard Worker 		// of this number.
194*5a6e8488SAndroid Build Coastguard Worker 		if (pt && last_pt) break;
195*5a6e8488SAndroid Build Coastguard Worker 
196*5a6e8488SAndroid Build Coastguard Worker 		// Set whether we have found a radix point.
197*5a6e8488SAndroid Build Coastguard Worker 		pt = pt || last_pt;
198*5a6e8488SAndroid Build Coastguard Worker 
199*5a6e8488SAndroid Build Coastguard Worker 		bc_vec_push(&l->str, &c);
200*5a6e8488SAndroid Build Coastguard Worker 	}
201*5a6e8488SAndroid Build Coastguard Worker 
202*5a6e8488SAndroid Build Coastguard Worker 	return i;
203*5a6e8488SAndroid Build Coastguard Worker }
204*5a6e8488SAndroid Build Coastguard Worker 
205*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_number(BcLex * l,char start)206*5a6e8488SAndroid Build Coastguard Worker bc_lex_number(BcLex* l, char start)
207*5a6e8488SAndroid Build Coastguard Worker {
208*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_NUMBER;
209*5a6e8488SAndroid Build Coastguard Worker 
210*5a6e8488SAndroid Build Coastguard Worker 	// Make sure the string is clear.
211*5a6e8488SAndroid Build Coastguard Worker 	bc_vec_popAll(&l->str);
212*5a6e8488SAndroid Build Coastguard Worker 	bc_vec_push(&l->str, &start);
213*5a6e8488SAndroid Build Coastguard Worker 
214*5a6e8488SAndroid Build Coastguard Worker 	// Parse the number.
215*5a6e8488SAndroid Build Coastguard Worker 	l->i += bc_lex_num(l, start, false);
216*5a6e8488SAndroid Build Coastguard Worker 
217*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
218*5a6e8488SAndroid Build Coastguard Worker 	{
219*5a6e8488SAndroid Build Coastguard Worker 		char c = l->buf[l->i];
220*5a6e8488SAndroid Build Coastguard Worker 
221*5a6e8488SAndroid Build Coastguard Worker 		// Do we have a number in scientific notation?
222*5a6e8488SAndroid Build Coastguard Worker 		if (c == 'e')
223*5a6e8488SAndroid Build Coastguard Worker 		{
224*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
225*5a6e8488SAndroid Build Coastguard Worker 			// Barf for POSIX.
226*5a6e8488SAndroid Build Coastguard Worker 			if (BC_IS_POSIX) bc_lex_err(l, BC_ERR_POSIX_EXP_NUM);
227*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
228*5a6e8488SAndroid Build Coastguard Worker 
229*5a6e8488SAndroid Build Coastguard Worker 			// Push the e.
230*5a6e8488SAndroid Build Coastguard Worker 			bc_vec_push(&l->str, &c);
231*5a6e8488SAndroid Build Coastguard Worker 			l->i += 1;
232*5a6e8488SAndroid Build Coastguard Worker 			c = l->buf[l->i];
233*5a6e8488SAndroid Build Coastguard Worker 
234*5a6e8488SAndroid Build Coastguard Worker 			// Check for negative specifically because bc_lex_num() does not.
235*5a6e8488SAndroid Build Coastguard Worker 			if (c == BC_LEX_NEG_CHAR)
236*5a6e8488SAndroid Build Coastguard Worker 			{
237*5a6e8488SAndroid Build Coastguard Worker 				bc_vec_push(&l->str, &c);
238*5a6e8488SAndroid Build Coastguard Worker 				l->i += 1;
239*5a6e8488SAndroid Build Coastguard Worker 				c = l->buf[l->i];
240*5a6e8488SAndroid Build Coastguard Worker 			}
241*5a6e8488SAndroid Build Coastguard Worker 
242*5a6e8488SAndroid Build Coastguard Worker 			// We must have a number character, so barf if not.
243*5a6e8488SAndroid Build Coastguard Worker 			if (BC_ERR(!BC_LEX_NUM_CHAR(c, false, true)))
244*5a6e8488SAndroid Build Coastguard Worker 			{
245*5a6e8488SAndroid Build Coastguard Worker 				bc_lex_verr(l, BC_ERR_PARSE_CHAR, c);
246*5a6e8488SAndroid Build Coastguard Worker 			}
247*5a6e8488SAndroid Build Coastguard Worker 
248*5a6e8488SAndroid Build Coastguard Worker 			// Parse the exponent.
249*5a6e8488SAndroid Build Coastguard Worker 			l->i += bc_lex_num(l, 0, true);
250*5a6e8488SAndroid Build Coastguard Worker 		}
251*5a6e8488SAndroid Build Coastguard Worker 	}
252*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
253*5a6e8488SAndroid Build Coastguard Worker 
254*5a6e8488SAndroid Build Coastguard Worker 	bc_vec_pushByte(&l->str, '\0');
255*5a6e8488SAndroid Build Coastguard Worker }
256*5a6e8488SAndroid Build Coastguard Worker 
257*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_name(BcLex * l)258*5a6e8488SAndroid Build Coastguard Worker bc_lex_name(BcLex* l)
259*5a6e8488SAndroid Build Coastguard Worker {
260*5a6e8488SAndroid Build Coastguard Worker 	size_t i = 0;
261*5a6e8488SAndroid Build Coastguard Worker 	const char* buf = l->buf + l->i - 1;
262*5a6e8488SAndroid Build Coastguard Worker 	char c = buf[i];
263*5a6e8488SAndroid Build Coastguard Worker 
264*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_NAME;
265*5a6e8488SAndroid Build Coastguard Worker 
266*5a6e8488SAndroid Build Coastguard Worker 	// Should be obvious. It's looking for valid characters.
267*5a6e8488SAndroid Build Coastguard Worker 	while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_')
268*5a6e8488SAndroid Build Coastguard Worker 	{
269*5a6e8488SAndroid Build Coastguard Worker 		c = buf[++i];
270*5a6e8488SAndroid Build Coastguard Worker 	}
271*5a6e8488SAndroid Build Coastguard Worker 
272*5a6e8488SAndroid Build Coastguard Worker 	// Set the string to the identifier.
273*5a6e8488SAndroid Build Coastguard Worker 	bc_vec_string(&l->str, i, buf);
274*5a6e8488SAndroid Build Coastguard Worker 
275*5a6e8488SAndroid Build Coastguard Worker 	// Increment the index. We minus 1 because it has already been incremented.
276*5a6e8488SAndroid Build Coastguard Worker 	l->i += i - 1;
277*5a6e8488SAndroid Build Coastguard Worker }
278*5a6e8488SAndroid Build Coastguard Worker 
279*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_init(BcLex * l)280*5a6e8488SAndroid Build Coastguard Worker bc_lex_init(BcLex* l)
281*5a6e8488SAndroid Build Coastguard Worker {
282*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
283*5a6e8488SAndroid Build Coastguard Worker 	assert(l != NULL);
284*5a6e8488SAndroid Build Coastguard Worker 	bc_vec_init(&l->str, sizeof(char), BC_DTOR_NONE);
285*5a6e8488SAndroid Build Coastguard Worker }
286*5a6e8488SAndroid Build Coastguard Worker 
287*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_free(BcLex * l)288*5a6e8488SAndroid Build Coastguard Worker bc_lex_free(BcLex* l)
289*5a6e8488SAndroid Build Coastguard Worker {
290*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
291*5a6e8488SAndroid Build Coastguard Worker 	assert(l != NULL);
292*5a6e8488SAndroid Build Coastguard Worker 	bc_vec_free(&l->str);
293*5a6e8488SAndroid Build Coastguard Worker }
294*5a6e8488SAndroid Build Coastguard Worker 
295*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_file(BcLex * l,const char * file)296*5a6e8488SAndroid Build Coastguard Worker bc_lex_file(BcLex* l, const char* file)
297*5a6e8488SAndroid Build Coastguard Worker {
298*5a6e8488SAndroid Build Coastguard Worker 	assert(l != NULL && file != NULL);
299*5a6e8488SAndroid Build Coastguard Worker 	l->line = 1;
300*5a6e8488SAndroid Build Coastguard Worker 	vm->file = file;
301*5a6e8488SAndroid Build Coastguard Worker }
302*5a6e8488SAndroid Build Coastguard Worker 
303*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_next(BcLex * l)304*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(BcLex* l)
305*5a6e8488SAndroid Build Coastguard Worker {
306*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
307*5a6e8488SAndroid Build Coastguard Worker 
308*5a6e8488SAndroid Build Coastguard Worker 	assert(l != NULL);
309*5a6e8488SAndroid Build Coastguard Worker 
310*5a6e8488SAndroid Build Coastguard Worker 	l->last = l->t;
311*5a6e8488SAndroid Build Coastguard Worker 
312*5a6e8488SAndroid Build Coastguard Worker 	// If this wasn't here, the line number would be off.
313*5a6e8488SAndroid Build Coastguard Worker 	l->line += (l->i != 0 && l->buf[l->i - 1] == '\n');
314*5a6e8488SAndroid Build Coastguard Worker 
315*5a6e8488SAndroid Build Coastguard Worker 	// If the last token was EOF, someone called this one too many times.
316*5a6e8488SAndroid Build Coastguard Worker 	if (BC_ERR(l->last == BC_LEX_EOF)) bc_lex_err(l, BC_ERR_PARSE_EOF);
317*5a6e8488SAndroid Build Coastguard Worker 
318*5a6e8488SAndroid Build Coastguard Worker 	l->t = BC_LEX_EOF;
319*5a6e8488SAndroid Build Coastguard Worker 
320*5a6e8488SAndroid Build Coastguard Worker 	// We are done if this is true.
321*5a6e8488SAndroid Build Coastguard Worker 	if (l->i == l->len) return;
322*5a6e8488SAndroid Build Coastguard Worker 
323*5a6e8488SAndroid Build Coastguard Worker 	// Loop until failure or we don't have whitespace. This
324*5a6e8488SAndroid Build Coastguard Worker 	// is so the parser doesn't get inundated with whitespace.
325*5a6e8488SAndroid Build Coastguard Worker 	do
326*5a6e8488SAndroid Build Coastguard Worker 	{
327*5a6e8488SAndroid Build Coastguard Worker 		vm->next(l);
328*5a6e8488SAndroid Build Coastguard Worker 	}
329*5a6e8488SAndroid Build Coastguard Worker 	while (l->t == BC_LEX_WHITESPACE);
330*5a6e8488SAndroid Build Coastguard Worker }
331*5a6e8488SAndroid Build Coastguard Worker 
332*5a6e8488SAndroid Build Coastguard Worker /**
333*5a6e8488SAndroid Build Coastguard Worker  * Updates the buffer and len so that they are not invalidated when the stdin
334*5a6e8488SAndroid Build Coastguard Worker  * buffer grows.
335*5a6e8488SAndroid Build Coastguard Worker  * @param l     The lexer.
336*5a6e8488SAndroid Build Coastguard Worker  * @param text  The text.
337*5a6e8488SAndroid Build Coastguard Worker  * @param len   The length of the text.
338*5a6e8488SAndroid Build Coastguard Worker  */
339*5a6e8488SAndroid Build Coastguard Worker static void
bc_lex_fixText(BcLex * l,const char * text,size_t len)340*5a6e8488SAndroid Build Coastguard Worker bc_lex_fixText(BcLex* l, const char* text, size_t len)
341*5a6e8488SAndroid Build Coastguard Worker {
342*5a6e8488SAndroid Build Coastguard Worker 	l->buf = text;
343*5a6e8488SAndroid Build Coastguard Worker 	l->len = len;
344*5a6e8488SAndroid Build Coastguard Worker }
345*5a6e8488SAndroid Build Coastguard Worker 
346*5a6e8488SAndroid Build Coastguard Worker bool
bc_lex_readLine(BcLex * l)347*5a6e8488SAndroid Build Coastguard Worker bc_lex_readLine(BcLex* l)
348*5a6e8488SAndroid Build Coastguard Worker {
349*5a6e8488SAndroid Build Coastguard Worker 	bool good;
350*5a6e8488SAndroid Build Coastguard Worker 
351*5a6e8488SAndroid Build Coastguard Worker 	// These are reversed because they should be already locked, but
352*5a6e8488SAndroid Build Coastguard Worker 	// bc_vm_readLine() needs them to be unlocked.
353*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_UNLOCK;
354*5a6e8488SAndroid Build Coastguard Worker 
355*5a6e8488SAndroid Build Coastguard Worker 	// Make sure we read from the appropriate place.
356*5a6e8488SAndroid Build Coastguard Worker 	switch (l->mode)
357*5a6e8488SAndroid Build Coastguard Worker 	{
358*5a6e8488SAndroid Build Coastguard Worker 		case BC_MODE_EXPRS:
359*5a6e8488SAndroid Build Coastguard Worker 		{
360*5a6e8488SAndroid Build Coastguard Worker 			good = bc_vm_readBuf(false);
361*5a6e8488SAndroid Build Coastguard Worker 			break;
362*5a6e8488SAndroid Build Coastguard Worker 		}
363*5a6e8488SAndroid Build Coastguard Worker 
364*5a6e8488SAndroid Build Coastguard Worker 		case BC_MODE_FILE:
365*5a6e8488SAndroid Build Coastguard Worker 		{
366*5a6e8488SAndroid Build Coastguard Worker 			good = false;
367*5a6e8488SAndroid Build Coastguard Worker 			break;
368*5a6e8488SAndroid Build Coastguard Worker 		}
369*5a6e8488SAndroid Build Coastguard Worker 
370*5a6e8488SAndroid Build Coastguard Worker #if !BC_ENABLE_OSSFUZZ
371*5a6e8488SAndroid Build Coastguard Worker 
372*5a6e8488SAndroid Build Coastguard Worker 		case BC_MODE_STDIN:
373*5a6e8488SAndroid Build Coastguard Worker 		{
374*5a6e8488SAndroid Build Coastguard Worker 			good = bc_vm_readLine(false);
375*5a6e8488SAndroid Build Coastguard Worker 			break;
376*5a6e8488SAndroid Build Coastguard Worker 		}
377*5a6e8488SAndroid Build Coastguard Worker 
378*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_ENABLE_OSSFUZZ
379*5a6e8488SAndroid Build Coastguard Worker 
380*5a6e8488SAndroid Build Coastguard Worker #ifdef __GNUC__
381*5a6e8488SAndroid Build Coastguard Worker #ifndef __clang__
382*5a6e8488SAndroid Build Coastguard Worker 		default:
383*5a6e8488SAndroid Build Coastguard Worker 		{
384*5a6e8488SAndroid Build Coastguard Worker 			// We should never get here.
385*5a6e8488SAndroid Build Coastguard Worker 			abort();
386*5a6e8488SAndroid Build Coastguard Worker 		}
387*5a6e8488SAndroid Build Coastguard Worker #endif // __clang__
388*5a6e8488SAndroid Build Coastguard Worker #endif // __GNUC__
389*5a6e8488SAndroid Build Coastguard Worker 	}
390*5a6e8488SAndroid Build Coastguard Worker 
391*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_LOCK;
392*5a6e8488SAndroid Build Coastguard Worker 
393*5a6e8488SAndroid Build Coastguard Worker 	bc_lex_fixText(l, vm->buffer.v, vm->buffer.len - 1);
394*5a6e8488SAndroid Build Coastguard Worker 
395*5a6e8488SAndroid Build Coastguard Worker 	return good;
396*5a6e8488SAndroid Build Coastguard Worker }
397*5a6e8488SAndroid Build Coastguard Worker 
398*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_text(BcLex * l,const char * text,BcMode mode)399*5a6e8488SAndroid Build Coastguard Worker bc_lex_text(BcLex* l, const char* text, BcMode mode)
400*5a6e8488SAndroid Build Coastguard Worker {
401*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
402*5a6e8488SAndroid Build Coastguard Worker 
403*5a6e8488SAndroid Build Coastguard Worker 	assert(l != NULL && text != NULL);
404*5a6e8488SAndroid Build Coastguard Worker 
405*5a6e8488SAndroid Build Coastguard Worker 	bc_lex_fixText(l, text, strlen(text));
406*5a6e8488SAndroid Build Coastguard Worker 	l->i = 0;
407*5a6e8488SAndroid Build Coastguard Worker 	l->t = l->last = BC_LEX_INVALID;
408*5a6e8488SAndroid Build Coastguard Worker 	l->mode = mode;
409*5a6e8488SAndroid Build Coastguard Worker 
410*5a6e8488SAndroid Build Coastguard Worker 	bc_lex_next(l);
411*5a6e8488SAndroid Build Coastguard Worker }
412