1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 4*3aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 6*3aa99676SStefan Eßer * Copyright (c) 2018-2020 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 32252884aeSStefan Eßer * Common code for the lexers. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #include <assert.h> 37252884aeSStefan Eßer #include <ctype.h> 38252884aeSStefan Eßer #include <stdbool.h> 39252884aeSStefan Eßer #include <string.h> 40252884aeSStefan Eßer 41252884aeSStefan Eßer #include <status.h> 42252884aeSStefan Eßer #include <lex.h> 43252884aeSStefan Eßer #include <vm.h> 44252884aeSStefan Eßer #include <bc.h> 45252884aeSStefan Eßer 46252884aeSStefan Eßer void bc_lex_invalidChar(BcLex *l, char c) { 47252884aeSStefan Eßer l->t = BC_LEX_INVALID; 48252884aeSStefan Eßer bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c); 49252884aeSStefan Eßer } 50252884aeSStefan Eßer 51252884aeSStefan Eßer void bc_lex_lineComment(BcLex *l) { 52252884aeSStefan Eßer l->t = BC_LEX_WHITESPACE; 53252884aeSStefan Eßer while (l->i < l->len && l->buf[l->i] != '\n') l->i += 1; 54252884aeSStefan Eßer } 55252884aeSStefan Eßer 56252884aeSStefan Eßer void bc_lex_comment(BcLex *l) { 57252884aeSStefan Eßer 58252884aeSStefan Eßer size_t i, nlines = 0; 59252884aeSStefan Eßer const char *buf = l->buf; 60252884aeSStefan Eßer bool end = false; 61252884aeSStefan Eßer char c; 62252884aeSStefan Eßer 63252884aeSStefan Eßer l->i += 1; 64252884aeSStefan Eßer l->t = BC_LEX_WHITESPACE; 65252884aeSStefan Eßer 66252884aeSStefan Eßer for (i = l->i; !end; i += !end) { 67252884aeSStefan Eßer 68252884aeSStefan Eßer for (; (c = buf[i]) && c != '*'; ++i) nlines += (c == '\n'); 69252884aeSStefan Eßer 70252884aeSStefan Eßer if (BC_ERR(!c || buf[i + 1] == '\0')) { 71252884aeSStefan Eßer l->i = i; 72252884aeSStefan Eßer bc_lex_err(l, BC_ERROR_PARSE_COMMENT); 73252884aeSStefan Eßer } 74252884aeSStefan Eßer 75252884aeSStefan Eßer end = buf[i + 1] == '/'; 76252884aeSStefan Eßer } 77252884aeSStefan Eßer 78252884aeSStefan Eßer l->i = i + 2; 79252884aeSStefan Eßer l->line += nlines; 80252884aeSStefan Eßer } 81252884aeSStefan Eßer 82252884aeSStefan Eßer void bc_lex_whitespace(BcLex *l) { 83252884aeSStefan Eßer char c; 84252884aeSStefan Eßer l->t = BC_LEX_WHITESPACE; 85252884aeSStefan Eßer for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]); 86252884aeSStefan Eßer } 87252884aeSStefan Eßer 88252884aeSStefan Eßer void bc_lex_commonTokens(BcLex *l, char c) { 89252884aeSStefan Eßer if (!c) l->t = BC_LEX_EOF; 90252884aeSStefan Eßer else if (c == '\n') l->t = BC_LEX_NLINE; 91252884aeSStefan Eßer else bc_lex_whitespace(l); 92252884aeSStefan Eßer } 93252884aeSStefan Eßer 94252884aeSStefan Eßer static size_t bc_lex_num(BcLex *l, char start, bool int_only) { 95252884aeSStefan Eßer 96252884aeSStefan Eßer const char *buf = l->buf + l->i; 97252884aeSStefan Eßer size_t i; 98252884aeSStefan Eßer char c; 99252884aeSStefan Eßer bool last_pt, pt = (start == '.'); 100252884aeSStefan Eßer 101252884aeSStefan Eßer for (i = 0; (c = buf[i]) && (BC_LEX_NUM_CHAR(c, pt, int_only) || 102252884aeSStefan Eßer (c == '\\' && buf[i + 1] == '\n')); ++i) 103252884aeSStefan Eßer { 104252884aeSStefan Eßer if (c == '\\') { 105252884aeSStefan Eßer 106252884aeSStefan Eßer if (buf[i + 1] == '\n') { 107252884aeSStefan Eßer 108252884aeSStefan Eßer i += 2; 109252884aeSStefan Eßer 110252884aeSStefan Eßer // Make sure to eat whitespace at the beginning of the line. 111252884aeSStefan Eßer while(isspace(buf[i]) && buf[i] != '\n') i += 1; 112252884aeSStefan Eßer 113252884aeSStefan Eßer c = buf[i]; 114252884aeSStefan Eßer 115252884aeSStefan Eßer if (!BC_LEX_NUM_CHAR(c, pt, int_only)) break; 116252884aeSStefan Eßer } 117252884aeSStefan Eßer else break; 118252884aeSStefan Eßer } 119252884aeSStefan Eßer 120252884aeSStefan Eßer last_pt = (c == '.'); 121252884aeSStefan Eßer if (pt && last_pt) break; 122252884aeSStefan Eßer pt = pt || last_pt; 123252884aeSStefan Eßer 124252884aeSStefan Eßer bc_vec_push(&l->str, &c); 125252884aeSStefan Eßer } 126252884aeSStefan Eßer 127252884aeSStefan Eßer return i; 128252884aeSStefan Eßer } 129252884aeSStefan Eßer 130252884aeSStefan Eßer void bc_lex_number(BcLex *l, char start) { 131252884aeSStefan Eßer 132252884aeSStefan Eßer l->t = BC_LEX_NUMBER; 133252884aeSStefan Eßer 134252884aeSStefan Eßer bc_vec_npop(&l->str, l->str.len); 135252884aeSStefan Eßer bc_vec_push(&l->str, &start); 136252884aeSStefan Eßer 137252884aeSStefan Eßer l->i += bc_lex_num(l, start, false); 138252884aeSStefan Eßer 139252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 140252884aeSStefan Eßer { 141252884aeSStefan Eßer char c = l->buf[l->i]; 142252884aeSStefan Eßer 143252884aeSStefan Eßer if (c == 'e') { 144252884aeSStefan Eßer 145252884aeSStefan Eßer #if BC_ENABLED 146252884aeSStefan Eßer if (BC_IS_POSIX) bc_lex_err(l, BC_ERROR_POSIX_EXP_NUM); 147252884aeSStefan Eßer #endif // BC_ENABLED 148252884aeSStefan Eßer 149252884aeSStefan Eßer bc_vec_push(&l->str, &c); 150252884aeSStefan Eßer l->i += 1; 151252884aeSStefan Eßer c = l->buf[l->i]; 152252884aeSStefan Eßer 153252884aeSStefan Eßer if (c == BC_LEX_NEG_CHAR) { 154252884aeSStefan Eßer bc_vec_push(&l->str, &c); 155252884aeSStefan Eßer l->i += 1; 156252884aeSStefan Eßer c = l->buf[l->i]; 157252884aeSStefan Eßer } 158252884aeSStefan Eßer 159252884aeSStefan Eßer if (BC_ERR(!BC_LEX_NUM_CHAR(c, false, true))) 160252884aeSStefan Eßer bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c); 161252884aeSStefan Eßer 162252884aeSStefan Eßer l->i += bc_lex_num(l, 0, true); 163252884aeSStefan Eßer } 164252884aeSStefan Eßer } 165252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 166252884aeSStefan Eßer 167252884aeSStefan Eßer bc_vec_pushByte(&l->str, '\0'); 168252884aeSStefan Eßer } 169252884aeSStefan Eßer 170252884aeSStefan Eßer void bc_lex_name(BcLex *l) { 171252884aeSStefan Eßer 172252884aeSStefan Eßer size_t i = 0; 173252884aeSStefan Eßer const char *buf = l->buf + l->i - 1; 174252884aeSStefan Eßer char c = buf[i]; 175252884aeSStefan Eßer 176252884aeSStefan Eßer l->t = BC_LEX_NAME; 177252884aeSStefan Eßer 178252884aeSStefan Eßer while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i]; 179252884aeSStefan Eßer 180252884aeSStefan Eßer bc_vec_string(&l->str, i, buf); 181252884aeSStefan Eßer 182252884aeSStefan Eßer // Increment the index. We minus 1 because it has already been incremented. 183252884aeSStefan Eßer l->i += i - 1; 184252884aeSStefan Eßer } 185252884aeSStefan Eßer 186252884aeSStefan Eßer void bc_lex_init(BcLex *l) { 187252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 188252884aeSStefan Eßer assert(l != NULL); 189252884aeSStefan Eßer bc_vec_init(&l->str, sizeof(char), NULL); 190252884aeSStefan Eßer } 191252884aeSStefan Eßer 192252884aeSStefan Eßer void bc_lex_free(BcLex *l) { 193252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 194252884aeSStefan Eßer assert(l != NULL); 195252884aeSStefan Eßer bc_vec_free(&l->str); 196252884aeSStefan Eßer } 197252884aeSStefan Eßer 198252884aeSStefan Eßer void bc_lex_file(BcLex *l, const char *file) { 199252884aeSStefan Eßer assert(l != NULL && file != NULL); 200252884aeSStefan Eßer l->line = 1; 201252884aeSStefan Eßer vm.file = file; 202252884aeSStefan Eßer } 203252884aeSStefan Eßer 204252884aeSStefan Eßer void bc_lex_next(BcLex *l) { 205252884aeSStefan Eßer 206252884aeSStefan Eßer assert(l != NULL); 207252884aeSStefan Eßer 208252884aeSStefan Eßer l->last = l->t; 209252884aeSStefan Eßer l->line += (l->i != 0 && l->buf[l->i - 1] == '\n'); 210252884aeSStefan Eßer 211252884aeSStefan Eßer if (BC_ERR(l->last == BC_LEX_EOF)) bc_lex_err(l, BC_ERROR_PARSE_EOF); 212252884aeSStefan Eßer 213252884aeSStefan Eßer l->t = BC_LEX_EOF; 214252884aeSStefan Eßer 215252884aeSStefan Eßer if (l->i == l->len) return; 216252884aeSStefan Eßer 217252884aeSStefan Eßer // Loop until failure or we don't have whitespace. This 218252884aeSStefan Eßer // is so the parser doesn't get inundated with whitespace. 219252884aeSStefan Eßer do { 220252884aeSStefan Eßer vm.next(l); 221252884aeSStefan Eßer } while (l->t == BC_LEX_WHITESPACE); 222252884aeSStefan Eßer } 223252884aeSStefan Eßer 224252884aeSStefan Eßer void bc_lex_text(BcLex *l, const char *text) { 225252884aeSStefan Eßer assert(l != NULL && text != NULL); 226252884aeSStefan Eßer l->buf = text; 227252884aeSStefan Eßer l->i = 0; 228252884aeSStefan Eßer l->len = strlen(text); 229252884aeSStefan Eßer l->t = l->last = BC_LEX_INVALID; 230252884aeSStefan Eßer bc_lex_next(l); 231252884aeSStefan Eßer } 232