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 * The lexer for bc.
33*5a6e8488SAndroid Build Coastguard Worker *
34*5a6e8488SAndroid Build Coastguard Worker */
35*5a6e8488SAndroid Build Coastguard Worker
36*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
37*5a6e8488SAndroid Build Coastguard Worker
38*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
39*5a6e8488SAndroid Build Coastguard Worker #include <ctype.h>
40*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
41*5a6e8488SAndroid Build Coastguard Worker
42*5a6e8488SAndroid Build Coastguard Worker #include <bc.h>
43*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
44*5a6e8488SAndroid Build Coastguard Worker
45*5a6e8488SAndroid Build Coastguard Worker /**
46*5a6e8488SAndroid Build Coastguard Worker * Lexes an identifier, which may be a keyword.
47*5a6e8488SAndroid Build Coastguard Worker * @param l The lexer.
48*5a6e8488SAndroid Build Coastguard Worker */
49*5a6e8488SAndroid Build Coastguard Worker static void
bc_lex_identifier(BcLex * l)50*5a6e8488SAndroid Build Coastguard Worker bc_lex_identifier(BcLex* l)
51*5a6e8488SAndroid Build Coastguard Worker {
52*5a6e8488SAndroid Build Coastguard Worker // We already passed the first character, so we need to be sure to include
53*5a6e8488SAndroid Build Coastguard Worker // it.
54*5a6e8488SAndroid Build Coastguard Worker const char* buf = l->buf + l->i - 1;
55*5a6e8488SAndroid Build Coastguard Worker size_t i;
56*5a6e8488SAndroid Build Coastguard Worker
57*5a6e8488SAndroid Build Coastguard Worker // This loop is simply checking for keywords.
58*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < bc_lex_kws_len; ++i)
59*5a6e8488SAndroid Build Coastguard Worker {
60*5a6e8488SAndroid Build Coastguard Worker const BcLexKeyword* kw = bc_lex_kws + i;
61*5a6e8488SAndroid Build Coastguard Worker size_t n = BC_LEX_KW_LEN(kw);
62*5a6e8488SAndroid Build Coastguard Worker
63*5a6e8488SAndroid Build Coastguard Worker if (!strncmp(buf, kw->name, n) && !isalnum(buf[n]) && buf[n] != '_')
64*5a6e8488SAndroid Build Coastguard Worker {
65*5a6e8488SAndroid Build Coastguard Worker // If the keyword has been redefined, and redefinition is allowed
66*5a6e8488SAndroid Build Coastguard Worker // (it is not allowed for builtin libraries), break out of the loop
67*5a6e8488SAndroid Build Coastguard Worker // and use it as a name. This depends on the argument parser to
68*5a6e8488SAndroid Build Coastguard Worker // ensure that only non-POSIX keywords get redefined.
69*5a6e8488SAndroid Build Coastguard Worker if (!vm->no_redefine && vm->redefined_kws[i]) break;
70*5a6e8488SAndroid Build Coastguard Worker
71*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_KW_AUTO + (BcLexType) i;
72*5a6e8488SAndroid Build Coastguard Worker
73*5a6e8488SAndroid Build Coastguard Worker // Warn or error, as appropriate for the mode, if the keyword is not
74*5a6e8488SAndroid Build Coastguard Worker // in the POSIX standard.
75*5a6e8488SAndroid Build Coastguard Worker if (!BC_LEX_KW_POSIX(kw)) bc_lex_verr(l, BC_ERR_POSIX_KW, kw->name);
76*5a6e8488SAndroid Build Coastguard Worker
77*5a6e8488SAndroid Build Coastguard Worker // We minus 1 because the index has already been incremented.
78*5a6e8488SAndroid Build Coastguard Worker l->i += n - 1;
79*5a6e8488SAndroid Build Coastguard Worker
80*5a6e8488SAndroid Build Coastguard Worker // Already have the token; bail.
81*5a6e8488SAndroid Build Coastguard Worker return;
82*5a6e8488SAndroid Build Coastguard Worker }
83*5a6e8488SAndroid Build Coastguard Worker }
84*5a6e8488SAndroid Build Coastguard Worker
85*5a6e8488SAndroid Build Coastguard Worker // If not a keyword, parse the name.
86*5a6e8488SAndroid Build Coastguard Worker bc_lex_name(l);
87*5a6e8488SAndroid Build Coastguard Worker
88*5a6e8488SAndroid Build Coastguard Worker // POSIX doesn't allow identifiers that are more than one character, so we
89*5a6e8488SAndroid Build Coastguard Worker // might have to warn or error here too.
90*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(l->str.len - 1 > 1))
91*5a6e8488SAndroid Build Coastguard Worker {
92*5a6e8488SAndroid Build Coastguard Worker bc_lex_verr(l, BC_ERR_POSIX_NAME_LEN, l->str.v);
93*5a6e8488SAndroid Build Coastguard Worker }
94*5a6e8488SAndroid Build Coastguard Worker }
95*5a6e8488SAndroid Build Coastguard Worker
96*5a6e8488SAndroid Build Coastguard Worker /**
97*5a6e8488SAndroid Build Coastguard Worker * Parses a bc string. This is separate from dc strings because dc strings need
98*5a6e8488SAndroid Build Coastguard Worker * to be balanced.
99*5a6e8488SAndroid Build Coastguard Worker * @param l The lexer.
100*5a6e8488SAndroid Build Coastguard Worker */
101*5a6e8488SAndroid Build Coastguard Worker static void
bc_lex_string(BcLex * l)102*5a6e8488SAndroid Build Coastguard Worker bc_lex_string(BcLex* l)
103*5a6e8488SAndroid Build Coastguard Worker {
104*5a6e8488SAndroid Build Coastguard Worker // We need to keep track of newlines to increment them properly.
105*5a6e8488SAndroid Build Coastguard Worker size_t len, nlines, i;
106*5a6e8488SAndroid Build Coastguard Worker const char* buf;
107*5a6e8488SAndroid Build Coastguard Worker char c;
108*5a6e8488SAndroid Build Coastguard Worker bool got_more;
109*5a6e8488SAndroid Build Coastguard Worker
110*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_STR;
111*5a6e8488SAndroid Build Coastguard Worker
112*5a6e8488SAndroid Build Coastguard Worker do
113*5a6e8488SAndroid Build Coastguard Worker {
114*5a6e8488SAndroid Build Coastguard Worker nlines = 0;
115*5a6e8488SAndroid Build Coastguard Worker buf = l->buf;
116*5a6e8488SAndroid Build Coastguard Worker got_more = false;
117*5a6e8488SAndroid Build Coastguard Worker
118*5a6e8488SAndroid Build Coastguard Worker #if !BC_ENABLE_OSSFUZZ
119*5a6e8488SAndroid Build Coastguard Worker assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v);
120*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_ENABLE_OSSFUZZ
121*5a6e8488SAndroid Build Coastguard Worker
122*5a6e8488SAndroid Build Coastguard Worker // Fortunately for us, bc doesn't escape quotes. Instead, the equivalent
123*5a6e8488SAndroid Build Coastguard Worker // is '\q', which makes this loop simpler.
124*5a6e8488SAndroid Build Coastguard Worker for (i = l->i; (c = buf[i]) && c != '"'; ++i)
125*5a6e8488SAndroid Build Coastguard Worker {
126*5a6e8488SAndroid Build Coastguard Worker nlines += (c == '\n');
127*5a6e8488SAndroid Build Coastguard Worker }
128*5a6e8488SAndroid Build Coastguard Worker
129*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(c == '\0') && !vm->eof && l->mode != BC_MODE_FILE)
130*5a6e8488SAndroid Build Coastguard Worker {
131*5a6e8488SAndroid Build Coastguard Worker got_more = bc_lex_readLine(l);
132*5a6e8488SAndroid Build Coastguard Worker }
133*5a6e8488SAndroid Build Coastguard Worker }
134*5a6e8488SAndroid Build Coastguard Worker while (got_more && c != '"');
135*5a6e8488SAndroid Build Coastguard Worker
136*5a6e8488SAndroid Build Coastguard Worker // If the string did not end properly, barf.
137*5a6e8488SAndroid Build Coastguard Worker if (c != '"')
138*5a6e8488SAndroid Build Coastguard Worker {
139*5a6e8488SAndroid Build Coastguard Worker l->i = i;
140*5a6e8488SAndroid Build Coastguard Worker bc_lex_err(l, BC_ERR_PARSE_STRING);
141*5a6e8488SAndroid Build Coastguard Worker }
142*5a6e8488SAndroid Build Coastguard Worker
143*5a6e8488SAndroid Build Coastguard Worker // Set the temp string to the parsed string.
144*5a6e8488SAndroid Build Coastguard Worker len = i - l->i;
145*5a6e8488SAndroid Build Coastguard Worker bc_vec_string(&l->str, len, l->buf + l->i);
146*5a6e8488SAndroid Build Coastguard Worker
147*5a6e8488SAndroid Build Coastguard Worker l->i = i + 1;
148*5a6e8488SAndroid Build Coastguard Worker l->line += nlines;
149*5a6e8488SAndroid Build Coastguard Worker }
150*5a6e8488SAndroid Build Coastguard Worker
151*5a6e8488SAndroid Build Coastguard Worker /**
152*5a6e8488SAndroid Build Coastguard Worker * This function takes a lexed operator and checks to see if it's the assignment
153*5a6e8488SAndroid Build Coastguard Worker * version, setting the token appropriately.
154*5a6e8488SAndroid Build Coastguard Worker * @param l The lexer.
155*5a6e8488SAndroid Build Coastguard Worker * @param with The token to assign if it is an assignment operator.
156*5a6e8488SAndroid Build Coastguard Worker * @param without The token to assign if it is not an assignment operator.
157*5a6e8488SAndroid Build Coastguard Worker */
158*5a6e8488SAndroid Build Coastguard Worker static void
bc_lex_assign(BcLex * l,BcLexType with,BcLexType without)159*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(BcLex* l, BcLexType with, BcLexType without)
160*5a6e8488SAndroid Build Coastguard Worker {
161*5a6e8488SAndroid Build Coastguard Worker if (l->buf[l->i] == '=')
162*5a6e8488SAndroid Build Coastguard Worker {
163*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
164*5a6e8488SAndroid Build Coastguard Worker l->t = with;
165*5a6e8488SAndroid Build Coastguard Worker }
166*5a6e8488SAndroid Build Coastguard Worker else l->t = without;
167*5a6e8488SAndroid Build Coastguard Worker }
168*5a6e8488SAndroid Build Coastguard Worker
169*5a6e8488SAndroid Build Coastguard Worker void
bc_lex_token(BcLex * l)170*5a6e8488SAndroid Build Coastguard Worker bc_lex_token(BcLex* l)
171*5a6e8488SAndroid Build Coastguard Worker {
172*5a6e8488SAndroid Build Coastguard Worker // We increment here. This means that all lexing needs to take that into
173*5a6e8488SAndroid Build Coastguard Worker // account, such as when parsing an identifier. If we don't, the first
174*5a6e8488SAndroid Build Coastguard Worker // character of every identifier would be missing.
175*5a6e8488SAndroid Build Coastguard Worker char c = l->buf[l->i++], c2;
176*5a6e8488SAndroid Build Coastguard Worker
177*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
178*5a6e8488SAndroid Build Coastguard Worker
179*5a6e8488SAndroid Build Coastguard Worker // This is the workhorse of the lexer.
180*5a6e8488SAndroid Build Coastguard Worker switch (c)
181*5a6e8488SAndroid Build Coastguard Worker {
182*5a6e8488SAndroid Build Coastguard Worker case '\0':
183*5a6e8488SAndroid Build Coastguard Worker case '\n':
184*5a6e8488SAndroid Build Coastguard Worker case '\t':
185*5a6e8488SAndroid Build Coastguard Worker case '\v':
186*5a6e8488SAndroid Build Coastguard Worker case '\f':
187*5a6e8488SAndroid Build Coastguard Worker case '\r':
188*5a6e8488SAndroid Build Coastguard Worker case ' ':
189*5a6e8488SAndroid Build Coastguard Worker {
190*5a6e8488SAndroid Build Coastguard Worker bc_lex_commonTokens(l, c);
191*5a6e8488SAndroid Build Coastguard Worker break;
192*5a6e8488SAndroid Build Coastguard Worker }
193*5a6e8488SAndroid Build Coastguard Worker
194*5a6e8488SAndroid Build Coastguard Worker case '!':
195*5a6e8488SAndroid Build Coastguard Worker {
196*5a6e8488SAndroid Build Coastguard Worker // Even though it's not an assignment, we can use this.
197*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
198*5a6e8488SAndroid Build Coastguard Worker
199*5a6e8488SAndroid Build Coastguard Worker // POSIX doesn't allow boolean not.
200*5a6e8488SAndroid Build Coastguard Worker if (l->t == BC_LEX_OP_BOOL_NOT)
201*5a6e8488SAndroid Build Coastguard Worker {
202*5a6e8488SAndroid Build Coastguard Worker bc_lex_verr(l, BC_ERR_POSIX_BOOL, "!");
203*5a6e8488SAndroid Build Coastguard Worker }
204*5a6e8488SAndroid Build Coastguard Worker
205*5a6e8488SAndroid Build Coastguard Worker break;
206*5a6e8488SAndroid Build Coastguard Worker }
207*5a6e8488SAndroid Build Coastguard Worker
208*5a6e8488SAndroid Build Coastguard Worker case '"':
209*5a6e8488SAndroid Build Coastguard Worker {
210*5a6e8488SAndroid Build Coastguard Worker bc_lex_string(l);
211*5a6e8488SAndroid Build Coastguard Worker break;
212*5a6e8488SAndroid Build Coastguard Worker }
213*5a6e8488SAndroid Build Coastguard Worker
214*5a6e8488SAndroid Build Coastguard Worker case '#':
215*5a6e8488SAndroid Build Coastguard Worker {
216*5a6e8488SAndroid Build Coastguard Worker // POSIX does not allow line comments.
217*5a6e8488SAndroid Build Coastguard Worker bc_lex_err(l, BC_ERR_POSIX_COMMENT);
218*5a6e8488SAndroid Build Coastguard Worker bc_lex_lineComment(l);
219*5a6e8488SAndroid Build Coastguard Worker break;
220*5a6e8488SAndroid Build Coastguard Worker }
221*5a6e8488SAndroid Build Coastguard Worker
222*5a6e8488SAndroid Build Coastguard Worker case '%':
223*5a6e8488SAndroid Build Coastguard Worker {
224*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
225*5a6e8488SAndroid Build Coastguard Worker break;
226*5a6e8488SAndroid Build Coastguard Worker }
227*5a6e8488SAndroid Build Coastguard Worker
228*5a6e8488SAndroid Build Coastguard Worker case '&':
229*5a6e8488SAndroid Build Coastguard Worker {
230*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
231*5a6e8488SAndroid Build Coastguard Worker
232*5a6e8488SAndroid Build Coastguard Worker // Either we have boolean and or an error. And boolean and is not
233*5a6e8488SAndroid Build Coastguard Worker // allowed by POSIX.
234*5a6e8488SAndroid Build Coastguard Worker if (BC_NO_ERR(c2 == '&'))
235*5a6e8488SAndroid Build Coastguard Worker {
236*5a6e8488SAndroid Build Coastguard Worker bc_lex_verr(l, BC_ERR_POSIX_BOOL, "&&");
237*5a6e8488SAndroid Build Coastguard Worker
238*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
239*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_OP_BOOL_AND;
240*5a6e8488SAndroid Build Coastguard Worker }
241*5a6e8488SAndroid Build Coastguard Worker else bc_lex_invalidChar(l, c);
242*5a6e8488SAndroid Build Coastguard Worker
243*5a6e8488SAndroid Build Coastguard Worker break;
244*5a6e8488SAndroid Build Coastguard Worker }
245*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
246*5a6e8488SAndroid Build Coastguard Worker case '$':
247*5a6e8488SAndroid Build Coastguard Worker {
248*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_OP_TRUNC;
249*5a6e8488SAndroid Build Coastguard Worker break;
250*5a6e8488SAndroid Build Coastguard Worker }
251*5a6e8488SAndroid Build Coastguard Worker
252*5a6e8488SAndroid Build Coastguard Worker case '@':
253*5a6e8488SAndroid Build Coastguard Worker {
254*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLACES, BC_LEX_OP_PLACES);
255*5a6e8488SAndroid Build Coastguard Worker break;
256*5a6e8488SAndroid Build Coastguard Worker }
257*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
258*5a6e8488SAndroid Build Coastguard Worker case '(':
259*5a6e8488SAndroid Build Coastguard Worker case ')':
260*5a6e8488SAndroid Build Coastguard Worker {
261*5a6e8488SAndroid Build Coastguard Worker l->t = (BcLexType) (c - '(' + BC_LEX_LPAREN);
262*5a6e8488SAndroid Build Coastguard Worker break;
263*5a6e8488SAndroid Build Coastguard Worker }
264*5a6e8488SAndroid Build Coastguard Worker
265*5a6e8488SAndroid Build Coastguard Worker case '*':
266*5a6e8488SAndroid Build Coastguard Worker {
267*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
268*5a6e8488SAndroid Build Coastguard Worker break;
269*5a6e8488SAndroid Build Coastguard Worker }
270*5a6e8488SAndroid Build Coastguard Worker
271*5a6e8488SAndroid Build Coastguard Worker case '+':
272*5a6e8488SAndroid Build Coastguard Worker {
273*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
274*5a6e8488SAndroid Build Coastguard Worker
275*5a6e8488SAndroid Build Coastguard Worker // Have to check for increment first.
276*5a6e8488SAndroid Build Coastguard Worker if (c2 == '+')
277*5a6e8488SAndroid Build Coastguard Worker {
278*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
279*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_OP_INC;
280*5a6e8488SAndroid Build Coastguard Worker }
281*5a6e8488SAndroid Build Coastguard Worker else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
282*5a6e8488SAndroid Build Coastguard Worker break;
283*5a6e8488SAndroid Build Coastguard Worker }
284*5a6e8488SAndroid Build Coastguard Worker
285*5a6e8488SAndroid Build Coastguard Worker case ',':
286*5a6e8488SAndroid Build Coastguard Worker {
287*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_COMMA;
288*5a6e8488SAndroid Build Coastguard Worker break;
289*5a6e8488SAndroid Build Coastguard Worker }
290*5a6e8488SAndroid Build Coastguard Worker
291*5a6e8488SAndroid Build Coastguard Worker case '-':
292*5a6e8488SAndroid Build Coastguard Worker {
293*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
294*5a6e8488SAndroid Build Coastguard Worker
295*5a6e8488SAndroid Build Coastguard Worker // Have to check for decrement first.
296*5a6e8488SAndroid Build Coastguard Worker if (c2 == '-')
297*5a6e8488SAndroid Build Coastguard Worker {
298*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
299*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_OP_DEC;
300*5a6e8488SAndroid Build Coastguard Worker }
301*5a6e8488SAndroid Build Coastguard Worker else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
302*5a6e8488SAndroid Build Coastguard Worker break;
303*5a6e8488SAndroid Build Coastguard Worker }
304*5a6e8488SAndroid Build Coastguard Worker
305*5a6e8488SAndroid Build Coastguard Worker case '.':
306*5a6e8488SAndroid Build Coastguard Worker {
307*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
308*5a6e8488SAndroid Build Coastguard Worker
309*5a6e8488SAndroid Build Coastguard Worker // If it's alone, it's an alias for last.
310*5a6e8488SAndroid Build Coastguard Worker if (BC_LEX_NUM_CHAR(c2, true, false)) bc_lex_number(l, c);
311*5a6e8488SAndroid Build Coastguard Worker else
312*5a6e8488SAndroid Build Coastguard Worker {
313*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_KW_LAST;
314*5a6e8488SAndroid Build Coastguard Worker bc_lex_err(l, BC_ERR_POSIX_DOT);
315*5a6e8488SAndroid Build Coastguard Worker }
316*5a6e8488SAndroid Build Coastguard Worker
317*5a6e8488SAndroid Build Coastguard Worker break;
318*5a6e8488SAndroid Build Coastguard Worker }
319*5a6e8488SAndroid Build Coastguard Worker
320*5a6e8488SAndroid Build Coastguard Worker case '/':
321*5a6e8488SAndroid Build Coastguard Worker {
322*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
323*5a6e8488SAndroid Build Coastguard Worker if (c2 == '*') bc_lex_comment(l);
324*5a6e8488SAndroid Build Coastguard Worker else bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
325*5a6e8488SAndroid Build Coastguard Worker break;
326*5a6e8488SAndroid Build Coastguard Worker }
327*5a6e8488SAndroid Build Coastguard Worker
328*5a6e8488SAndroid Build Coastguard Worker case '0':
329*5a6e8488SAndroid Build Coastguard Worker case '1':
330*5a6e8488SAndroid Build Coastguard Worker case '2':
331*5a6e8488SAndroid Build Coastguard Worker case '3':
332*5a6e8488SAndroid Build Coastguard Worker case '4':
333*5a6e8488SAndroid Build Coastguard Worker case '5':
334*5a6e8488SAndroid Build Coastguard Worker case '6':
335*5a6e8488SAndroid Build Coastguard Worker case '7':
336*5a6e8488SAndroid Build Coastguard Worker case '8':
337*5a6e8488SAndroid Build Coastguard Worker case '9':
338*5a6e8488SAndroid Build Coastguard Worker case 'A':
339*5a6e8488SAndroid Build Coastguard Worker case 'B':
340*5a6e8488SAndroid Build Coastguard Worker case 'C':
341*5a6e8488SAndroid Build Coastguard Worker case 'D':
342*5a6e8488SAndroid Build Coastguard Worker case 'E':
343*5a6e8488SAndroid Build Coastguard Worker case 'F':
344*5a6e8488SAndroid Build Coastguard Worker // Apparently, GNU bc (and maybe others) allows any uppercase letter as
345*5a6e8488SAndroid Build Coastguard Worker // a number. When single digits, they act like the ones above. When
346*5a6e8488SAndroid Build Coastguard Worker // multi-digit, any letter above the input base is automatically set to
347*5a6e8488SAndroid Build Coastguard Worker // the biggest allowable digit in the input base.
348*5a6e8488SAndroid Build Coastguard Worker case 'G':
349*5a6e8488SAndroid Build Coastguard Worker case 'H':
350*5a6e8488SAndroid Build Coastguard Worker case 'I':
351*5a6e8488SAndroid Build Coastguard Worker case 'J':
352*5a6e8488SAndroid Build Coastguard Worker case 'K':
353*5a6e8488SAndroid Build Coastguard Worker case 'L':
354*5a6e8488SAndroid Build Coastguard Worker case 'M':
355*5a6e8488SAndroid Build Coastguard Worker case 'N':
356*5a6e8488SAndroid Build Coastguard Worker case 'O':
357*5a6e8488SAndroid Build Coastguard Worker case 'P':
358*5a6e8488SAndroid Build Coastguard Worker case 'Q':
359*5a6e8488SAndroid Build Coastguard Worker case 'R':
360*5a6e8488SAndroid Build Coastguard Worker case 'S':
361*5a6e8488SAndroid Build Coastguard Worker case 'T':
362*5a6e8488SAndroid Build Coastguard Worker case 'U':
363*5a6e8488SAndroid Build Coastguard Worker case 'V':
364*5a6e8488SAndroid Build Coastguard Worker case 'W':
365*5a6e8488SAndroid Build Coastguard Worker case 'X':
366*5a6e8488SAndroid Build Coastguard Worker case 'Y':
367*5a6e8488SAndroid Build Coastguard Worker case 'Z':
368*5a6e8488SAndroid Build Coastguard Worker {
369*5a6e8488SAndroid Build Coastguard Worker bc_lex_number(l, c);
370*5a6e8488SAndroid Build Coastguard Worker break;
371*5a6e8488SAndroid Build Coastguard Worker }
372*5a6e8488SAndroid Build Coastguard Worker
373*5a6e8488SAndroid Build Coastguard Worker case ';':
374*5a6e8488SAndroid Build Coastguard Worker {
375*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_SCOLON;
376*5a6e8488SAndroid Build Coastguard Worker break;
377*5a6e8488SAndroid Build Coastguard Worker }
378*5a6e8488SAndroid Build Coastguard Worker
379*5a6e8488SAndroid Build Coastguard Worker case '<':
380*5a6e8488SAndroid Build Coastguard Worker {
381*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
382*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
383*5a6e8488SAndroid Build Coastguard Worker
384*5a6e8488SAndroid Build Coastguard Worker // Check for shift.
385*5a6e8488SAndroid Build Coastguard Worker if (c2 == '<')
386*5a6e8488SAndroid Build Coastguard Worker {
387*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
388*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_ASSIGN_LSHIFT, BC_LEX_OP_LSHIFT);
389*5a6e8488SAndroid Build Coastguard Worker break;
390*5a6e8488SAndroid Build Coastguard Worker }
391*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
392*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
393*5a6e8488SAndroid Build Coastguard Worker break;
394*5a6e8488SAndroid Build Coastguard Worker }
395*5a6e8488SAndroid Build Coastguard Worker
396*5a6e8488SAndroid Build Coastguard Worker case '=':
397*5a6e8488SAndroid Build Coastguard Worker {
398*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
399*5a6e8488SAndroid Build Coastguard Worker break;
400*5a6e8488SAndroid Build Coastguard Worker }
401*5a6e8488SAndroid Build Coastguard Worker
402*5a6e8488SAndroid Build Coastguard Worker case '>':
403*5a6e8488SAndroid Build Coastguard Worker {
404*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
405*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
406*5a6e8488SAndroid Build Coastguard Worker
407*5a6e8488SAndroid Build Coastguard Worker // Check for shift.
408*5a6e8488SAndroid Build Coastguard Worker if (c2 == '>')
409*5a6e8488SAndroid Build Coastguard Worker {
410*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
411*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_ASSIGN_RSHIFT, BC_LEX_OP_RSHIFT);
412*5a6e8488SAndroid Build Coastguard Worker break;
413*5a6e8488SAndroid Build Coastguard Worker }
414*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
415*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
416*5a6e8488SAndroid Build Coastguard Worker break;
417*5a6e8488SAndroid Build Coastguard Worker }
418*5a6e8488SAndroid Build Coastguard Worker
419*5a6e8488SAndroid Build Coastguard Worker case '[':
420*5a6e8488SAndroid Build Coastguard Worker case ']':
421*5a6e8488SAndroid Build Coastguard Worker {
422*5a6e8488SAndroid Build Coastguard Worker l->t = (BcLexType) (c - '[' + BC_LEX_LBRACKET);
423*5a6e8488SAndroid Build Coastguard Worker break;
424*5a6e8488SAndroid Build Coastguard Worker }
425*5a6e8488SAndroid Build Coastguard Worker
426*5a6e8488SAndroid Build Coastguard Worker case '\\':
427*5a6e8488SAndroid Build Coastguard Worker {
428*5a6e8488SAndroid Build Coastguard Worker // In bc, a backslash+newline is whitespace.
429*5a6e8488SAndroid Build Coastguard Worker if (BC_NO_ERR(l->buf[l->i] == '\n'))
430*5a6e8488SAndroid Build Coastguard Worker {
431*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
432*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_WHITESPACE;
433*5a6e8488SAndroid Build Coastguard Worker }
434*5a6e8488SAndroid Build Coastguard Worker else bc_lex_invalidChar(l, c);
435*5a6e8488SAndroid Build Coastguard Worker break;
436*5a6e8488SAndroid Build Coastguard Worker }
437*5a6e8488SAndroid Build Coastguard Worker
438*5a6e8488SAndroid Build Coastguard Worker case '^':
439*5a6e8488SAndroid Build Coastguard Worker {
440*5a6e8488SAndroid Build Coastguard Worker bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
441*5a6e8488SAndroid Build Coastguard Worker break;
442*5a6e8488SAndroid Build Coastguard Worker }
443*5a6e8488SAndroid Build Coastguard Worker
444*5a6e8488SAndroid Build Coastguard Worker case 'a':
445*5a6e8488SAndroid Build Coastguard Worker case 'b':
446*5a6e8488SAndroid Build Coastguard Worker case 'c':
447*5a6e8488SAndroid Build Coastguard Worker case 'd':
448*5a6e8488SAndroid Build Coastguard Worker case 'e':
449*5a6e8488SAndroid Build Coastguard Worker case 'f':
450*5a6e8488SAndroid Build Coastguard Worker case 'g':
451*5a6e8488SAndroid Build Coastguard Worker case 'h':
452*5a6e8488SAndroid Build Coastguard Worker case 'i':
453*5a6e8488SAndroid Build Coastguard Worker case 'j':
454*5a6e8488SAndroid Build Coastguard Worker case 'k':
455*5a6e8488SAndroid Build Coastguard Worker case 'l':
456*5a6e8488SAndroid Build Coastguard Worker case 'm':
457*5a6e8488SAndroid Build Coastguard Worker case 'n':
458*5a6e8488SAndroid Build Coastguard Worker case 'o':
459*5a6e8488SAndroid Build Coastguard Worker case 'p':
460*5a6e8488SAndroid Build Coastguard Worker case 'q':
461*5a6e8488SAndroid Build Coastguard Worker case 'r':
462*5a6e8488SAndroid Build Coastguard Worker case 's':
463*5a6e8488SAndroid Build Coastguard Worker case 't':
464*5a6e8488SAndroid Build Coastguard Worker case 'u':
465*5a6e8488SAndroid Build Coastguard Worker case 'v':
466*5a6e8488SAndroid Build Coastguard Worker case 'w':
467*5a6e8488SAndroid Build Coastguard Worker case 'x':
468*5a6e8488SAndroid Build Coastguard Worker case 'y':
469*5a6e8488SAndroid Build Coastguard Worker case 'z':
470*5a6e8488SAndroid Build Coastguard Worker {
471*5a6e8488SAndroid Build Coastguard Worker bc_lex_identifier(l);
472*5a6e8488SAndroid Build Coastguard Worker break;
473*5a6e8488SAndroid Build Coastguard Worker }
474*5a6e8488SAndroid Build Coastguard Worker
475*5a6e8488SAndroid Build Coastguard Worker case '{':
476*5a6e8488SAndroid Build Coastguard Worker case '}':
477*5a6e8488SAndroid Build Coastguard Worker {
478*5a6e8488SAndroid Build Coastguard Worker l->t = (BcLexType) (c - '{' + BC_LEX_LBRACE);
479*5a6e8488SAndroid Build Coastguard Worker break;
480*5a6e8488SAndroid Build Coastguard Worker }
481*5a6e8488SAndroid Build Coastguard Worker
482*5a6e8488SAndroid Build Coastguard Worker case '|':
483*5a6e8488SAndroid Build Coastguard Worker {
484*5a6e8488SAndroid Build Coastguard Worker c2 = l->buf[l->i];
485*5a6e8488SAndroid Build Coastguard Worker
486*5a6e8488SAndroid Build Coastguard Worker // Once again, boolean or is not allowed by POSIX.
487*5a6e8488SAndroid Build Coastguard Worker if (BC_NO_ERR(c2 == '|'))
488*5a6e8488SAndroid Build Coastguard Worker {
489*5a6e8488SAndroid Build Coastguard Worker bc_lex_verr(l, BC_ERR_POSIX_BOOL, "||");
490*5a6e8488SAndroid Build Coastguard Worker
491*5a6e8488SAndroid Build Coastguard Worker l->i += 1;
492*5a6e8488SAndroid Build Coastguard Worker l->t = BC_LEX_OP_BOOL_OR;
493*5a6e8488SAndroid Build Coastguard Worker }
494*5a6e8488SAndroid Build Coastguard Worker else bc_lex_invalidChar(l, c);
495*5a6e8488SAndroid Build Coastguard Worker
496*5a6e8488SAndroid Build Coastguard Worker break;
497*5a6e8488SAndroid Build Coastguard Worker }
498*5a6e8488SAndroid Build Coastguard Worker
499*5a6e8488SAndroid Build Coastguard Worker default:
500*5a6e8488SAndroid Build Coastguard Worker {
501*5a6e8488SAndroid Build Coastguard Worker bc_lex_invalidChar(l, c);
502*5a6e8488SAndroid Build Coastguard Worker }
503*5a6e8488SAndroid Build Coastguard Worker }
504*5a6e8488SAndroid Build Coastguard Worker }
505*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
506