150696a6eSStefan Eßer /* 250696a6eSStefan Eßer * ***************************************************************************** 350696a6eSStefan Eßer * 450696a6eSStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 550696a6eSStefan Eßer * 6a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 750696a6eSStefan Eßer * 850696a6eSStefan Eßer * Redistribution and use in source and binary forms, with or without 950696a6eSStefan Eßer * modification, are permitted provided that the following conditions are met: 1050696a6eSStefan Eßer * 1150696a6eSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 1250696a6eSStefan Eßer * list of conditions and the following disclaimer. 1350696a6eSStefan Eßer * 1450696a6eSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 1550696a6eSStefan Eßer * this list of conditions and the following disclaimer in the documentation 1650696a6eSStefan Eßer * and/or other materials provided with the distribution. 1750696a6eSStefan Eßer * 1850696a6eSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1950696a6eSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2050696a6eSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2150696a6eSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2250696a6eSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2350696a6eSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2450696a6eSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2550696a6eSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2650696a6eSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2750696a6eSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2850696a6eSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 2950696a6eSStefan Eßer * 3050696a6eSStefan Eßer * ***************************************************************************** 3150696a6eSStefan Eßer * 3250696a6eSStefan Eßer * The lexer for bc. 3350696a6eSStefan Eßer * 3450696a6eSStefan Eßer */ 3550696a6eSStefan Eßer 3650696a6eSStefan Eßer #if BC_ENABLED 3750696a6eSStefan Eßer 3850696a6eSStefan Eßer #include <assert.h> 3950696a6eSStefan Eßer #include <ctype.h> 4050696a6eSStefan Eßer #include <string.h> 4150696a6eSStefan Eßer 4250696a6eSStefan Eßer #include <bc.h> 4350696a6eSStefan Eßer #include <vm.h> 4450696a6eSStefan Eßer 4544d4804dSStefan Eßer /** 4644d4804dSStefan Eßer * Lexes an identifier, which may be a keyword. 4744d4804dSStefan Eßer * @param l The lexer. 4844d4804dSStefan Eßer */ 4978bc019dSStefan Eßer static void 5078bc019dSStefan Eßer bc_lex_identifier(BcLex* l) 5178bc019dSStefan Eßer { 5244d4804dSStefan Eßer // We already passed the first character, so we need to be sure to include 5344d4804dSStefan Eßer // it. 5450696a6eSStefan Eßer const char* buf = l->buf + l->i - 1; 5544d4804dSStefan Eßer size_t i; 5650696a6eSStefan Eßer 5744d4804dSStefan Eßer // This loop is simply checking for keywords. 5878bc019dSStefan Eßer for (i = 0; i < bc_lex_kws_len; ++i) 5978bc019dSStefan Eßer { 6050696a6eSStefan Eßer const BcLexKeyword* kw = bc_lex_kws + i; 6150696a6eSStefan Eßer size_t n = BC_LEX_KW_LEN(kw); 6250696a6eSStefan Eßer 6378bc019dSStefan Eßer if (!strncmp(buf, kw->name, n) && !isalnum(buf[n]) && buf[n] != '_') 6478bc019dSStefan Eßer { 6544d4804dSStefan Eßer // If the keyword has been redefined, and redefinition is allowed 6644d4804dSStefan Eßer // (it is not allowed for builtin libraries), break out of the loop 6744d4804dSStefan Eßer // and use it as a name. This depends on the argument parser to 6844d4804dSStefan Eßer // ensure that only non-POSIX keywords get redefined. 69d101cdd6SStefan Eßer if (!vm->no_redefine && vm->redefined_kws[i]) break; 7044d4804dSStefan Eßer 7150696a6eSStefan Eßer l->t = BC_LEX_KW_AUTO + (BcLexType) i; 7250696a6eSStefan Eßer 7344d4804dSStefan Eßer // Warn or error, as appropriate for the mode, if the keyword is not 7444d4804dSStefan Eßer // in the POSIX standard. 7544d4804dSStefan Eßer if (!BC_LEX_KW_POSIX(kw)) bc_lex_verr(l, BC_ERR_POSIX_KW, kw->name); 7650696a6eSStefan Eßer 7750696a6eSStefan Eßer // We minus 1 because the index has already been incremented. 7850696a6eSStefan Eßer l->i += n - 1; 7944d4804dSStefan Eßer 8044d4804dSStefan Eßer // Already have the token; bail. 8150696a6eSStefan Eßer return; 8250696a6eSStefan Eßer } 8350696a6eSStefan Eßer } 8450696a6eSStefan Eßer 8544d4804dSStefan Eßer // If not a keyword, parse the name. 8650696a6eSStefan Eßer bc_lex_name(l); 8750696a6eSStefan Eßer 8844d4804dSStefan Eßer // POSIX doesn't allow identifiers that are more than one character, so we 8944d4804dSStefan Eßer // might have to warn or error here too. 9050696a6eSStefan Eßer if (BC_ERR(l->str.len - 1 > 1)) 9178bc019dSStefan Eßer { 9250696a6eSStefan Eßer bc_lex_verr(l, BC_ERR_POSIX_NAME_LEN, l->str.v); 9350696a6eSStefan Eßer } 9478bc019dSStefan Eßer } 9550696a6eSStefan Eßer 9644d4804dSStefan Eßer /** 9744d4804dSStefan Eßer * Parses a bc string. This is separate from dc strings because dc strings need 9844d4804dSStefan Eßer * to be balanced. 9944d4804dSStefan Eßer * @param l The lexer. 10044d4804dSStefan Eßer */ 10178bc019dSStefan Eßer static void 10278bc019dSStefan Eßer bc_lex_string(BcLex* l) 10378bc019dSStefan Eßer { 10444d4804dSStefan Eßer // We need to keep track of newlines to increment them properly. 10544d4804dSStefan Eßer size_t len, nlines, i; 10644d4804dSStefan Eßer const char* buf; 10750696a6eSStefan Eßer char c; 10844d4804dSStefan Eßer bool got_more; 10950696a6eSStefan Eßer 11050696a6eSStefan Eßer l->t = BC_LEX_STR; 11150696a6eSStefan Eßer 11278bc019dSStefan Eßer do 11378bc019dSStefan Eßer { 11444d4804dSStefan Eßer nlines = 0; 11544d4804dSStefan Eßer buf = l->buf; 11644d4804dSStefan Eßer got_more = false; 11744d4804dSStefan Eßer 118*12e0d316SStefan Eßer #if !BC_ENABLE_OSSFUZZ 119d101cdd6SStefan Eßer assert(vm->mode != BC_MODE_STDIN || buf == vm->buffer.v); 120*12e0d316SStefan Eßer #endif // !BC_ENABLE_OSSFUZZ 12144d4804dSStefan Eßer 12244d4804dSStefan Eßer // Fortunately for us, bc doesn't escape quotes. Instead, the equivalent 12344d4804dSStefan Eßer // is '\q', which makes this loop simpler. 12478bc019dSStefan Eßer for (i = l->i; (c = buf[i]) && c != '"'; ++i) 12578bc019dSStefan Eßer { 12678bc019dSStefan Eßer nlines += (c == '\n'); 12778bc019dSStefan Eßer } 12844d4804dSStefan Eßer 129d101cdd6SStefan Eßer if (BC_ERR(c == '\0') && !vm->eof && l->mode != BC_MODE_FILE) 13078bc019dSStefan Eßer { 13144d4804dSStefan Eßer got_more = bc_lex_readLine(l); 13278bc019dSStefan Eßer } 13378bc019dSStefan Eßer } 13478bc019dSStefan Eßer while (got_more && c != '"'); 13544d4804dSStefan Eßer 13644d4804dSStefan Eßer // If the string did not end properly, barf. 13778bc019dSStefan Eßer if (c != '"') 13878bc019dSStefan Eßer { 13950696a6eSStefan Eßer l->i = i; 14050696a6eSStefan Eßer bc_lex_err(l, BC_ERR_PARSE_STRING); 14150696a6eSStefan Eßer } 14250696a6eSStefan Eßer 14344d4804dSStefan Eßer // Set the temp string to the parsed string. 14450696a6eSStefan Eßer len = i - l->i; 14550696a6eSStefan Eßer bc_vec_string(&l->str, len, l->buf + l->i); 14650696a6eSStefan Eßer 14750696a6eSStefan Eßer l->i = i + 1; 14850696a6eSStefan Eßer l->line += nlines; 14950696a6eSStefan Eßer } 15050696a6eSStefan Eßer 15144d4804dSStefan Eßer /** 15244d4804dSStefan Eßer * This function takes a lexed operator and checks to see if it's the assignment 15344d4804dSStefan Eßer * version, setting the token appropriately. 15444d4804dSStefan Eßer * @param l The lexer. 15544d4804dSStefan Eßer * @param with The token to assign if it is an assignment operator. 15644d4804dSStefan Eßer * @param without The token to assign if it is not an assignment operator. 15744d4804dSStefan Eßer */ 15878bc019dSStefan Eßer static void 15978bc019dSStefan Eßer bc_lex_assign(BcLex* l, BcLexType with, BcLexType without) 16078bc019dSStefan Eßer { 16178bc019dSStefan Eßer if (l->buf[l->i] == '=') 16278bc019dSStefan Eßer { 16350696a6eSStefan Eßer l->i += 1; 16450696a6eSStefan Eßer l->t = with; 16550696a6eSStefan Eßer } 16650696a6eSStefan Eßer else l->t = without; 16750696a6eSStefan Eßer } 16850696a6eSStefan Eßer 16978bc019dSStefan Eßer void 17078bc019dSStefan Eßer bc_lex_token(BcLex* l) 17178bc019dSStefan Eßer { 17244d4804dSStefan Eßer // We increment here. This means that all lexing needs to take that into 17344d4804dSStefan Eßer // account, such as when parsing an identifier. If we don't, the first 17444d4804dSStefan Eßer // character of every identifier would be missing. 17550696a6eSStefan Eßer char c = l->buf[l->i++], c2; 17650696a6eSStefan Eßer 17710041e99SStefan Eßer BC_SIG_ASSERT_LOCKED; 17810041e99SStefan Eßer 17950696a6eSStefan Eßer // This is the workhorse of the lexer. 18078bc019dSStefan Eßer switch (c) 18178bc019dSStefan Eßer { 18250696a6eSStefan Eßer case '\0': 18350696a6eSStefan Eßer case '\n': 18450696a6eSStefan Eßer case '\t': 18550696a6eSStefan Eßer case '\v': 18650696a6eSStefan Eßer case '\f': 18750696a6eSStefan Eßer case '\r': 18850696a6eSStefan Eßer case ' ': 18950696a6eSStefan Eßer { 19050696a6eSStefan Eßer bc_lex_commonTokens(l, c); 19150696a6eSStefan Eßer break; 19250696a6eSStefan Eßer } 19350696a6eSStefan Eßer 19450696a6eSStefan Eßer case '!': 19550696a6eSStefan Eßer { 19644d4804dSStefan Eßer // Even though it's not an assignment, we can use this. 19750696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT); 19850696a6eSStefan Eßer 19944d4804dSStefan Eßer // POSIX doesn't allow boolean not. 20050696a6eSStefan Eßer if (l->t == BC_LEX_OP_BOOL_NOT) 20178bc019dSStefan Eßer { 20250696a6eSStefan Eßer bc_lex_verr(l, BC_ERR_POSIX_BOOL, "!"); 20378bc019dSStefan Eßer } 20450696a6eSStefan Eßer 20550696a6eSStefan Eßer break; 20650696a6eSStefan Eßer } 20750696a6eSStefan Eßer 20850696a6eSStefan Eßer case '"': 20950696a6eSStefan Eßer { 21050696a6eSStefan Eßer bc_lex_string(l); 21150696a6eSStefan Eßer break; 21250696a6eSStefan Eßer } 21350696a6eSStefan Eßer 21450696a6eSStefan Eßer case '#': 21550696a6eSStefan Eßer { 21644d4804dSStefan Eßer // POSIX does not allow line comments. 21750696a6eSStefan Eßer bc_lex_err(l, BC_ERR_POSIX_COMMENT); 21850696a6eSStefan Eßer bc_lex_lineComment(l); 21950696a6eSStefan Eßer break; 22050696a6eSStefan Eßer } 22150696a6eSStefan Eßer 22250696a6eSStefan Eßer case '%': 22350696a6eSStefan Eßer { 22450696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS); 22550696a6eSStefan Eßer break; 22650696a6eSStefan Eßer } 22750696a6eSStefan Eßer 22850696a6eSStefan Eßer case '&': 22950696a6eSStefan Eßer { 23050696a6eSStefan Eßer c2 = l->buf[l->i]; 23144d4804dSStefan Eßer 23244d4804dSStefan Eßer // Either we have boolean and or an error. And boolean and is not 23344d4804dSStefan Eßer // allowed by POSIX. 23478bc019dSStefan Eßer if (BC_NO_ERR(c2 == '&')) 23578bc019dSStefan Eßer { 23650696a6eSStefan Eßer bc_lex_verr(l, BC_ERR_POSIX_BOOL, "&&"); 23750696a6eSStefan Eßer 23850696a6eSStefan Eßer l->i += 1; 23950696a6eSStefan Eßer l->t = BC_LEX_OP_BOOL_AND; 24050696a6eSStefan Eßer } 24150696a6eSStefan Eßer else bc_lex_invalidChar(l, c); 24250696a6eSStefan Eßer 24350696a6eSStefan Eßer break; 24450696a6eSStefan Eßer } 24550696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH 24650696a6eSStefan Eßer case '$': 24750696a6eSStefan Eßer { 24850696a6eSStefan Eßer l->t = BC_LEX_OP_TRUNC; 24950696a6eSStefan Eßer break; 25050696a6eSStefan Eßer } 25150696a6eSStefan Eßer 25250696a6eSStefan Eßer case '@': 25350696a6eSStefan Eßer { 25450696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLACES, BC_LEX_OP_PLACES); 25550696a6eSStefan Eßer break; 25650696a6eSStefan Eßer } 25750696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 25850696a6eSStefan Eßer case '(': 25950696a6eSStefan Eßer case ')': 26050696a6eSStefan Eßer { 26150696a6eSStefan Eßer l->t = (BcLexType) (c - '(' + BC_LEX_LPAREN); 26250696a6eSStefan Eßer break; 26350696a6eSStefan Eßer } 26450696a6eSStefan Eßer 26550696a6eSStefan Eßer case '*': 26650696a6eSStefan Eßer { 26750696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY); 26850696a6eSStefan Eßer break; 26950696a6eSStefan Eßer } 27050696a6eSStefan Eßer 27150696a6eSStefan Eßer case '+': 27250696a6eSStefan Eßer { 27350696a6eSStefan Eßer c2 = l->buf[l->i]; 27444d4804dSStefan Eßer 27544d4804dSStefan Eßer // Have to check for increment first. 27678bc019dSStefan Eßer if (c2 == '+') 27778bc019dSStefan Eßer { 27850696a6eSStefan Eßer l->i += 1; 27950696a6eSStefan Eßer l->t = BC_LEX_OP_INC; 28050696a6eSStefan Eßer } 28150696a6eSStefan Eßer else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS); 28250696a6eSStefan Eßer break; 28350696a6eSStefan Eßer } 28450696a6eSStefan Eßer 28550696a6eSStefan Eßer case ',': 28650696a6eSStefan Eßer { 28750696a6eSStefan Eßer l->t = BC_LEX_COMMA; 28850696a6eSStefan Eßer break; 28950696a6eSStefan Eßer } 29050696a6eSStefan Eßer 29150696a6eSStefan Eßer case '-': 29250696a6eSStefan Eßer { 29350696a6eSStefan Eßer c2 = l->buf[l->i]; 29444d4804dSStefan Eßer 29544d4804dSStefan Eßer // Have to check for decrement first. 29678bc019dSStefan Eßer if (c2 == '-') 29778bc019dSStefan Eßer { 29850696a6eSStefan Eßer l->i += 1; 29950696a6eSStefan Eßer l->t = BC_LEX_OP_DEC; 30050696a6eSStefan Eßer } 30150696a6eSStefan Eßer else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS); 30250696a6eSStefan Eßer break; 30350696a6eSStefan Eßer } 30450696a6eSStefan Eßer 30550696a6eSStefan Eßer case '.': 30650696a6eSStefan Eßer { 30750696a6eSStefan Eßer c2 = l->buf[l->i]; 30844d4804dSStefan Eßer 30944d4804dSStefan Eßer // If it's alone, it's an alias for last. 31050696a6eSStefan Eßer if (BC_LEX_NUM_CHAR(c2, true, false)) bc_lex_number(l, c); 31178bc019dSStefan Eßer else 31278bc019dSStefan Eßer { 31350696a6eSStefan Eßer l->t = BC_LEX_KW_LAST; 31450696a6eSStefan Eßer bc_lex_err(l, BC_ERR_POSIX_DOT); 31550696a6eSStefan Eßer } 31644d4804dSStefan Eßer 31750696a6eSStefan Eßer break; 31850696a6eSStefan Eßer } 31950696a6eSStefan Eßer 32050696a6eSStefan Eßer case '/': 32150696a6eSStefan Eßer { 32250696a6eSStefan Eßer c2 = l->buf[l->i]; 32350696a6eSStefan Eßer if (c2 == '*') bc_lex_comment(l); 32450696a6eSStefan Eßer else bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE); 32550696a6eSStefan Eßer break; 32650696a6eSStefan Eßer } 32750696a6eSStefan Eßer 32850696a6eSStefan Eßer case '0': 32950696a6eSStefan Eßer case '1': 33050696a6eSStefan Eßer case '2': 33150696a6eSStefan Eßer case '3': 33250696a6eSStefan Eßer case '4': 33350696a6eSStefan Eßer case '5': 33450696a6eSStefan Eßer case '6': 33550696a6eSStefan Eßer case '7': 33650696a6eSStefan Eßer case '8': 33750696a6eSStefan Eßer case '9': 33850696a6eSStefan Eßer case 'A': 33950696a6eSStefan Eßer case 'B': 34050696a6eSStefan Eßer case 'C': 34150696a6eSStefan Eßer case 'D': 34250696a6eSStefan Eßer case 'E': 34350696a6eSStefan Eßer case 'F': 34450696a6eSStefan Eßer // Apparently, GNU bc (and maybe others) allows any uppercase letter as 34550696a6eSStefan Eßer // a number. When single digits, they act like the ones above. When 34650696a6eSStefan Eßer // multi-digit, any letter above the input base is automatically set to 34750696a6eSStefan Eßer // the biggest allowable digit in the input base. 34850696a6eSStefan Eßer case 'G': 34950696a6eSStefan Eßer case 'H': 35050696a6eSStefan Eßer case 'I': 35150696a6eSStefan Eßer case 'J': 35250696a6eSStefan Eßer case 'K': 35350696a6eSStefan Eßer case 'L': 35450696a6eSStefan Eßer case 'M': 35550696a6eSStefan Eßer case 'N': 35650696a6eSStefan Eßer case 'O': 35750696a6eSStefan Eßer case 'P': 35850696a6eSStefan Eßer case 'Q': 35950696a6eSStefan Eßer case 'R': 36050696a6eSStefan Eßer case 'S': 36150696a6eSStefan Eßer case 'T': 36250696a6eSStefan Eßer case 'U': 36350696a6eSStefan Eßer case 'V': 36450696a6eSStefan Eßer case 'W': 36550696a6eSStefan Eßer case 'X': 36650696a6eSStefan Eßer case 'Y': 36750696a6eSStefan Eßer case 'Z': 36850696a6eSStefan Eßer { 36950696a6eSStefan Eßer bc_lex_number(l, c); 37050696a6eSStefan Eßer break; 37150696a6eSStefan Eßer } 37250696a6eSStefan Eßer 37350696a6eSStefan Eßer case ';': 37450696a6eSStefan Eßer { 37550696a6eSStefan Eßer l->t = BC_LEX_SCOLON; 37650696a6eSStefan Eßer break; 37750696a6eSStefan Eßer } 37850696a6eSStefan Eßer 37950696a6eSStefan Eßer case '<': 38050696a6eSStefan Eßer { 38150696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH 38250696a6eSStefan Eßer c2 = l->buf[l->i]; 38350696a6eSStefan Eßer 38444d4804dSStefan Eßer // Check for shift. 38578bc019dSStefan Eßer if (c2 == '<') 38678bc019dSStefan Eßer { 38750696a6eSStefan Eßer l->i += 1; 38850696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_ASSIGN_LSHIFT, BC_LEX_OP_LSHIFT); 38950696a6eSStefan Eßer break; 39050696a6eSStefan Eßer } 39150696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 39250696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT); 39350696a6eSStefan Eßer break; 39450696a6eSStefan Eßer } 39550696a6eSStefan Eßer 39650696a6eSStefan Eßer case '=': 39750696a6eSStefan Eßer { 39850696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN); 39950696a6eSStefan Eßer break; 40050696a6eSStefan Eßer } 40150696a6eSStefan Eßer 40250696a6eSStefan Eßer case '>': 40350696a6eSStefan Eßer { 40450696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH 40550696a6eSStefan Eßer c2 = l->buf[l->i]; 40650696a6eSStefan Eßer 40744d4804dSStefan Eßer // Check for shift. 40878bc019dSStefan Eßer if (c2 == '>') 40978bc019dSStefan Eßer { 41050696a6eSStefan Eßer l->i += 1; 41150696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_ASSIGN_RSHIFT, BC_LEX_OP_RSHIFT); 41250696a6eSStefan Eßer break; 41350696a6eSStefan Eßer } 41450696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 41550696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT); 41650696a6eSStefan Eßer break; 41750696a6eSStefan Eßer } 41850696a6eSStefan Eßer 41950696a6eSStefan Eßer case '[': 42050696a6eSStefan Eßer case ']': 42150696a6eSStefan Eßer { 42250696a6eSStefan Eßer l->t = (BcLexType) (c - '[' + BC_LEX_LBRACKET); 42350696a6eSStefan Eßer break; 42450696a6eSStefan Eßer } 42550696a6eSStefan Eßer 42650696a6eSStefan Eßer case '\\': 42750696a6eSStefan Eßer { 42844d4804dSStefan Eßer // In bc, a backslash+newline is whitespace. 42978bc019dSStefan Eßer if (BC_NO_ERR(l->buf[l->i] == '\n')) 43078bc019dSStefan Eßer { 43150696a6eSStefan Eßer l->i += 1; 43250696a6eSStefan Eßer l->t = BC_LEX_WHITESPACE; 43350696a6eSStefan Eßer } 43450696a6eSStefan Eßer else bc_lex_invalidChar(l, c); 43550696a6eSStefan Eßer break; 43650696a6eSStefan Eßer } 43750696a6eSStefan Eßer 43850696a6eSStefan Eßer case '^': 43950696a6eSStefan Eßer { 44050696a6eSStefan Eßer bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER); 44150696a6eSStefan Eßer break; 44250696a6eSStefan Eßer } 44350696a6eSStefan Eßer 44450696a6eSStefan Eßer case 'a': 44550696a6eSStefan Eßer case 'b': 44650696a6eSStefan Eßer case 'c': 44750696a6eSStefan Eßer case 'd': 44850696a6eSStefan Eßer case 'e': 44950696a6eSStefan Eßer case 'f': 45050696a6eSStefan Eßer case 'g': 45150696a6eSStefan Eßer case 'h': 45250696a6eSStefan Eßer case 'i': 45350696a6eSStefan Eßer case 'j': 45450696a6eSStefan Eßer case 'k': 45550696a6eSStefan Eßer case 'l': 45650696a6eSStefan Eßer case 'm': 45750696a6eSStefan Eßer case 'n': 45850696a6eSStefan Eßer case 'o': 45950696a6eSStefan Eßer case 'p': 46050696a6eSStefan Eßer case 'q': 46150696a6eSStefan Eßer case 'r': 46250696a6eSStefan Eßer case 's': 46350696a6eSStefan Eßer case 't': 46450696a6eSStefan Eßer case 'u': 46550696a6eSStefan Eßer case 'v': 46650696a6eSStefan Eßer case 'w': 46750696a6eSStefan Eßer case 'x': 46850696a6eSStefan Eßer case 'y': 46950696a6eSStefan Eßer case 'z': 47050696a6eSStefan Eßer { 47150696a6eSStefan Eßer bc_lex_identifier(l); 47250696a6eSStefan Eßer break; 47350696a6eSStefan Eßer } 47450696a6eSStefan Eßer 47550696a6eSStefan Eßer case '{': 47650696a6eSStefan Eßer case '}': 47750696a6eSStefan Eßer { 47850696a6eSStefan Eßer l->t = (BcLexType) (c - '{' + BC_LEX_LBRACE); 47950696a6eSStefan Eßer break; 48050696a6eSStefan Eßer } 48150696a6eSStefan Eßer 48250696a6eSStefan Eßer case '|': 48350696a6eSStefan Eßer { 48450696a6eSStefan Eßer c2 = l->buf[l->i]; 48550696a6eSStefan Eßer 48644d4804dSStefan Eßer // Once again, boolean or is not allowed by POSIX. 48778bc019dSStefan Eßer if (BC_NO_ERR(c2 == '|')) 48878bc019dSStefan Eßer { 48950696a6eSStefan Eßer bc_lex_verr(l, BC_ERR_POSIX_BOOL, "||"); 49050696a6eSStefan Eßer 49150696a6eSStefan Eßer l->i += 1; 49250696a6eSStefan Eßer l->t = BC_LEX_OP_BOOL_OR; 49350696a6eSStefan Eßer } 49450696a6eSStefan Eßer else bc_lex_invalidChar(l, c); 49550696a6eSStefan Eßer 49650696a6eSStefan Eßer break; 49750696a6eSStefan Eßer } 49850696a6eSStefan Eßer 49950696a6eSStefan Eßer default: 50050696a6eSStefan Eßer { 50150696a6eSStefan Eßer bc_lex_invalidChar(l, c); 50250696a6eSStefan Eßer } 50350696a6eSStefan Eßer } 50450696a6eSStefan Eßer } 50550696a6eSStefan Eßer #endif // BC_ENABLED 506