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