1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * The lexer for dc. 33 * 34 */ 35 36 #if DC_ENABLED 37 38 #include <ctype.h> 39 40 #include <dc.h> 41 #include <vm.h> 42 43 bool dc_lex_negCommand(BcLex *l) { 44 char c = l->buf[l->i]; 45 return !BC_LEX_NUM_CHAR(c, false, false); 46 } 47 48 static void dc_lex_register(BcLex *l) { 49 50 if (DC_X && isspace(l->buf[l->i - 1])) { 51 52 char c; 53 54 bc_lex_whitespace(l); 55 c = l->buf[l->i]; 56 57 if (!isalnum(c) && c != '_') 58 bc_lex_verr(l, BC_ERR_PARSE_CHAR, c); 59 60 l->i += 1; 61 bc_lex_name(l); 62 } 63 else { 64 bc_vec_popAll(&l->str); 65 bc_vec_pushByte(&l->str, (uchar) l->buf[l->i - 1]); 66 bc_vec_pushByte(&l->str, '\0'); 67 l->t = BC_LEX_NAME; 68 } 69 } 70 71 static void dc_lex_string(BcLex *l) { 72 73 size_t depth = 1, nls = 0, i = l->i; 74 char c; 75 76 l->t = BC_LEX_STR; 77 bc_vec_popAll(&l->str); 78 79 for (; (c = l->buf[i]) && depth; ++i) { 80 81 if (c == '\\') { 82 c = l->buf[++i]; 83 if (!c) break; 84 } 85 else { 86 depth += (c == '['); 87 depth -= (c == ']'); 88 } 89 90 nls += (c == '\n'); 91 92 if (depth) bc_vec_push(&l->str, &c); 93 } 94 95 if (BC_ERR(c == '\0' && depth)) { 96 l->i = i; 97 bc_lex_err(l, BC_ERR_PARSE_STRING); 98 } 99 100 bc_vec_pushByte(&l->str, '\0'); 101 102 l->i = i; 103 l->line += nls; 104 } 105 106 void dc_lex_token(BcLex *l) { 107 108 char c = l->buf[l->i++], c2; 109 size_t i; 110 111 for (i = 0; i < dc_lex_regs_len; ++i) { 112 if (l->last == dc_lex_regs[i]) { 113 dc_lex_register(l); 114 return; 115 } 116 } 117 118 if (c >= '"' && c <= '~' && 119 (l->t = dc_lex_tokens[(c - '"')]) != BC_LEX_INVALID) 120 { 121 return; 122 } 123 124 // This is the workhorse of the lexer. 125 switch (c) { 126 127 case '\0': 128 case '\n': 129 case '\t': 130 case '\v': 131 case '\f': 132 case '\r': 133 case ' ': 134 { 135 bc_lex_commonTokens(l, c); 136 break; 137 } 138 139 case '!': 140 { 141 c2 = l->buf[l->i]; 142 143 if (c2 == '=') l->t = BC_LEX_OP_REL_NE; 144 else if (c2 == '<') l->t = BC_LEX_OP_REL_LE; 145 else if (c2 == '>') l->t = BC_LEX_OP_REL_GE; 146 else bc_lex_invalidChar(l, c); 147 148 l->i += 1; 149 break; 150 } 151 152 case '#': 153 { 154 bc_lex_lineComment(l); 155 break; 156 } 157 158 case '.': 159 { 160 c2 = l->buf[l->i]; 161 if (BC_NO_ERR(BC_LEX_NUM_CHAR(c2, true, false))) 162 bc_lex_number(l, c); 163 else bc_lex_invalidChar(l, c); 164 break; 165 } 166 167 case '0': 168 case '1': 169 case '2': 170 case '3': 171 case '4': 172 case '5': 173 case '6': 174 case '7': 175 case '8': 176 case '9': 177 case 'A': 178 case 'B': 179 case 'C': 180 case 'D': 181 case 'E': 182 case 'F': 183 { 184 bc_lex_number(l, c); 185 break; 186 } 187 188 case '[': 189 { 190 dc_lex_string(l); 191 break; 192 } 193 194 default: 195 { 196 bc_lex_invalidChar(l, c); 197 } 198 } 199 } 200 #endif // DC_ENABLED 201