Gavin Howard | 5715b04 | 2018-02-12 16:11:42 -0700 | [diff] [blame] | 1 | /* |
Gavin Howard | b5904bf | 2018-02-20 13:28:18 -0700 | [diff] [blame] | 2 | * ***************************************************************************** |
Gavin Howard | 5715b04 | 2018-02-12 16:11:42 -0700 | [diff] [blame] | 3 | * |
Gavin Howard | b5904bf | 2018-02-20 13:28:18 -0700 | [diff] [blame] | 4 | * Copyright 2018 Gavin D. Howard |
Gavin Howard | 5715b04 | 2018-02-12 16:11:42 -0700 | [diff] [blame] | 5 | * |
| 6 | * Permission to use, copy, modify, and/or distribute this software for any |
| 7 | * purpose with or without fee is hereby granted. |
| 8 | * |
| 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH |
| 10 | * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
| 11 | * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, |
| 12 | * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM |
| 13 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR |
| 14 | * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 15 | * PERFORMANCE OF THIS SOFTWARE. |
| 16 | * |
Gavin Howard | b5904bf | 2018-02-20 13:28:18 -0700 | [diff] [blame] | 17 | * ***************************************************************************** |
Gavin Howard | 5715b04 | 2018-02-12 16:11:42 -0700 | [diff] [blame] | 18 | * |
| 19 | * The lexer. |
| 20 | * |
| 21 | */ |
| 22 | |
Gavin Howard | 27fdfb9 | 2018-03-21 07:56:59 -0600 | [diff] [blame] | 23 | #include <assert.h> |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 24 | #include <ctype.h> |
| 25 | #include <stdbool.h> |
| 26 | #include <stdint.h> |
| 27 | #include <stdio.h> |
| 28 | #include <stdlib.h> |
| 29 | #include <string.h> |
| 30 | |
Gavin Howard | 2949306 | 2018-03-20 19:57:37 -0600 | [diff] [blame] | 31 | #include <status.h> |
Gavin Howard | 3ba6c8d | 2018-02-15 12:23:35 -0700 | [diff] [blame] | 32 | #include <lex.h> |
Gavin Howard | 2949306 | 2018-03-20 19:57:37 -0600 | [diff] [blame] | 33 | #include <bc.h> |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 34 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 35 | BcStatus bc_lex_string(BcLex *lex) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 36 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 37 | const char *start; |
Gavin Howard | 4cf4992 | 2018-03-12 17:13:50 -0600 | [diff] [blame] | 38 | size_t newlines, len, i, j; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 39 | char c; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 40 | |
| 41 | newlines = 0; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 42 | lex->token.type = BC_LEX_STRING; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 43 | i = lex->idx; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 44 | |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 45 | for (c = lex->buffer[i]; c != '"' && c != '\0'; c = lex->buffer[++i]) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 46 | if (c == '\n') ++newlines; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | if (c == '\0') { |
| 50 | lex->idx = i; |
| 51 | return BC_STATUS_LEX_NO_STRING_END; |
| 52 | } |
| 53 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 54 | len = i - lex->idx; |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 55 | if (!(lex->token.string = malloc(len + 1))) return BC_STATUS_MALLOC_FAIL; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 56 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 57 | start = lex->buffer + lex->idx; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 58 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 59 | for (j = 0; j < len; ++j) lex->token.string[j] = start[j]; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 60 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 61 | lex->token.string[len] = '\0'; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 62 | lex->idx = i + 1; |
| 63 | lex->line += newlines; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 64 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 65 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 66 | } |
| 67 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 68 | BcStatus bc_lex_comment(BcLex *lex) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 69 | |
Gavin Howard | 6b5f5bb | 2018-03-22 23:16:57 -0600 | [diff] [blame] | 70 | size_t newlines, i; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 71 | const char *buffer; |
Gavin Howard | 6b5f5bb | 2018-03-22 23:16:57 -0600 | [diff] [blame] | 72 | bool end; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 73 | |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 74 | newlines = 0; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 75 | lex->token.type = BC_LEX_WHITESPACE; |
Gavin Howard | e7149d0 | 2018-03-21 20:09:22 -0600 | [diff] [blame] | 76 | end = false; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 77 | |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 78 | buffer = lex->buffer; |
| 79 | |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 80 | for (i = ++lex->idx; !end; i += !end) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 81 | |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 82 | char c; |
| 83 | |
| 84 | for (; (c = buffer[i]) != '*' && c != '\0'; ++i) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 85 | if (c == '\n') ++newlines; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | if (c == '\0' || buffer[i + 1] == '\0') { |
| 89 | lex->idx = i; |
| 90 | return BC_STATUS_LEX_NO_COMMENT_END; |
| 91 | } |
| 92 | |
| 93 | end = buffer[i + 1] == '/'; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | lex->idx = i + 2; |
| 97 | lex->line += newlines; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 98 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 99 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 100 | } |
| 101 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 102 | BcStatus bc_lex_number(BcLex *lex, char start) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 103 | |
Gavin Howard | 6b5f5bb | 2018-03-22 23:16:57 -0600 | [diff] [blame] | 104 | const char *buffer, *buf; |
| 105 | size_t backslashes, len, hits, i, j; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 106 | char c; |
| 107 | bool point; |
| 108 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 109 | lex->token.type = BC_LEX_NUMBER; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 110 | point = start == '.'; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 111 | buffer = lex->buffer + lex->idx; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 112 | backslashes = 0; |
| 113 | i = 0; |
| 114 | c = buffer[i]; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 115 | |
| 116 | while (c && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || |
| 117 | (c == '.' && !point) || (c == '\\' && buffer[i + 1] == '\n'))) |
| 118 | { |
| 119 | if (c == '\\') { |
| 120 | ++i; |
| 121 | backslashes += 1; |
| 122 | } |
| 123 | |
| 124 | c = buffer[++i]; |
| 125 | } |
| 126 | |
Gavin Howard | 117de42 | 2018-03-24 15:04:50 -0600 | [diff] [blame] | 127 | len = i + 1 * (*(buffer + i - 1) != '.'); |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 128 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 129 | lex->token.string = malloc(len - backslashes * 2 + 1); |
| 130 | if (!lex->token.string) return BC_STATUS_MALLOC_FAIL; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 131 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 132 | lex->token.string[0] = start; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 133 | buf = buffer - 1; |
| 134 | hits = 0; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 135 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 136 | for (j = 1; j < len; ++j) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 137 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 138 | c = buf[j]; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 139 | |
| 140 | // If we have hit a backslash, skip it. |
| 141 | // We don't have to check for a newline |
| 142 | // because it's guaranteed. |
| 143 | if (hits < backslashes && c == '\\') { |
| 144 | ++hits; |
| 145 | ++j; |
| 146 | continue; |
| 147 | } |
| 148 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 149 | lex->token.string[j - (hits * 2)] = c; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 150 | } |
| 151 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 152 | lex->token.string[j - (hits * 2)] = '\0'; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 153 | lex->idx += i; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 154 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 155 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 156 | } |
| 157 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 158 | BcStatus bc_lex_name(BcLex *lex) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 159 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 160 | BcStatus status; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 161 | const char *buffer; |
| 162 | size_t i; |
| 163 | char c; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 164 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 165 | buffer = lex->buffer + lex->idx - 1; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 166 | |
Gavin Howard | ceb0d6e | 2018-03-10 11:19:09 -0700 | [diff] [blame] | 167 | for (i = 0; i < sizeof(bc_lex_keywords) / sizeof(bc_lex_keywords[0]); ++i) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 168 | |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 169 | unsigned long len = (unsigned long) bc_lex_keywords[i].len; |
| 170 | if (!strncmp(buffer, bc_lex_keywords[i].name, len)) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 171 | |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 172 | lex->token.type = BC_LEX_KEY_AUTO + (BcLexToken) i; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 173 | |
Gavin Howard | ceb0d6e | 2018-03-10 11:19:09 -0700 | [diff] [blame] | 174 | if (!bc_lex_keywords[i].posix && |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 175 | (status = bc_posix_error(BC_STATUS_POSIX_BAD_KEYWORD, lex->file, |
| 176 | lex->line, bc_lex_keywords[i].name))) |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 177 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 178 | return status; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | // We need to minus one because the |
| 182 | // index has already been incremented. |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 183 | lex->idx += (unsigned long) bc_lex_keywords[i].len - 1; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 184 | |
| 185 | return BC_STATUS_SUCCESS; |
| 186 | } |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 187 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 188 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 189 | lex->token.type = BC_LEX_NAME; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 190 | |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 191 | i = 0; |
| 192 | c = buffer[i]; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 193 | |
Gavin Howard | e7149d0 | 2018-03-21 20:09:22 -0600 | [diff] [blame] | 194 | while ((c >= 'a' && c<= 'z') || (c >= '0' && c <= '9') || c == '_') |
| 195 | c = buffer[++i]; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 196 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 197 | if (i > 1 && (status = bc_posix_error(BC_STATUS_POSIX_NAME_LEN, |
| 198 | lex->file, lex->line, buffer))) |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 199 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 200 | return status; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 201 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 202 | |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 203 | if (!(lex->token.string = malloc(i + 1))) return BC_STATUS_MALLOC_FAIL; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 204 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 205 | strncpy(lex->token.string, buffer, i); |
| 206 | lex->token.string[i] = '\0'; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 207 | |
| 208 | // Increment the index. It is minus one |
| 209 | // because it has already been incremented. |
| 210 | lex->idx += i - 1; |
| 211 | |
| 212 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 213 | } |
| 214 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 215 | BcStatus bc_lex_token(BcLex *lex) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 216 | |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 217 | BcStatus status = BC_STATUS_SUCCESS; |
Gavin Howard | 6b5f5bb | 2018-03-22 23:16:57 -0600 | [diff] [blame] | 218 | char c, c2; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 219 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 220 | // This is the workhorse of the lexer. |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 221 | switch ((c = lex->buffer[lex->idx++])) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 222 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 223 | case '\0': |
Gavin Howard | c312ab3 | 2018-03-29 15:47:10 -0600 | [diff] [blame] | 224 | case '\n': |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 225 | { |
Gavin Howard | a58294c | 2018-03-24 14:07:28 -0600 | [diff] [blame] | 226 | lex->newline = true; |
Gavin Howard | c312ab3 | 2018-03-29 15:47:10 -0600 | [diff] [blame] | 227 | lex->token.type = BC_LEX_NEWLINE + (!c) * (BC_LEX_EOF - BC_LEX_NEWLINE); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 228 | break; |
| 229 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 230 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 231 | case '\t': |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 232 | case '\v': |
| 233 | case '\f': |
| 234 | case '\r': |
| 235 | case ' ': |
Gavin Howard | c312ab3 | 2018-03-29 15:47:10 -0600 | [diff] [blame] | 236 | case '\\': |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 237 | { |
Gavin Howard | c312ab3 | 2018-03-29 15:47:10 -0600 | [diff] [blame] | 238 | lex->token.type = BC_LEX_WHITESPACE; |
Gavin Howard | ce1069c | 2018-03-29 17:38:42 -0600 | [diff] [blame] | 239 | c = lex->buffer[lex->idx]; |
| 240 | |
Gavin Howard | c312ab3 | 2018-03-29 15:47:10 -0600 | [diff] [blame] | 241 | while ((isspace(c) && c != '\n') || c == '\\') |
| 242 | c = lex->buffer[++lex->idx]; |
| 243 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 244 | break; |
| 245 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 246 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 247 | case '!': |
| 248 | { |
| 249 | c2 = lex->buffer[lex->idx]; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 250 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 251 | if (c2 == '=') { |
| 252 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 253 | lex->token.type = BC_LEX_OP_REL_NOT_EQ; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 254 | } |
| 255 | else { |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 256 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 257 | if ((status = bc_posix_error(BC_STATUS_POSIX_BOOL_OPS, |
| 258 | lex->file, lex->line, "!"))) |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 259 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 260 | return status; |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 261 | } |
| 262 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 263 | lex->token.type = BC_LEX_OP_BOOL_NOT; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 264 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 265 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 266 | break; |
| 267 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 268 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 269 | case '"': |
| 270 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 271 | status = bc_lex_string(lex); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 272 | break; |
| 273 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 274 | |
Gavin Howard | 3eeff83 | 2018-01-31 12:57:54 -0700 | [diff] [blame] | 275 | case '#': |
| 276 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 277 | if ((status = bc_posix_error(BC_STATUS_POSIX_SCRIPT_COMMENT, |
| 278 | lex->file, lex->line, NULL))) |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 279 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 280 | return status; |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 281 | } |
Gavin Howard | 3eeff83 | 2018-01-31 12:57:54 -0700 | [diff] [blame] | 282 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 283 | lex->token.type = BC_LEX_WHITESPACE; |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 284 | while (++lex->idx < lex->len && lex->buffer[lex->idx] != '\n'); |
Gavin Howard | 3eeff83 | 2018-01-31 12:57:54 -0700 | [diff] [blame] | 285 | |
| 286 | break; |
| 287 | } |
| 288 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 289 | case '%': |
| 290 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 291 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 292 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 293 | lex->token.type = BC_LEX_OP_ASSIGN_MODULUS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 294 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 295 | else lex->token.type = BC_LEX_OP_MODULUS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 296 | break; |
| 297 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 298 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 299 | case '&': |
| 300 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 301 | if ((c2 = lex->buffer[lex->idx]) == '&') { |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 302 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 303 | if ((status = bc_posix_error(BC_STATUS_POSIX_BOOL_OPS, |
| 304 | lex->file, lex->line, "&&"))) |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 305 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 306 | return status; |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 307 | } |
| 308 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 309 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 310 | lex->token.type = BC_LEX_OP_BOOL_AND; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 311 | } |
| 312 | else { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 313 | lex->token.type = BC_LEX_INVALID; |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 314 | status = BC_STATUS_LEX_BAD_CHARACTER; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 315 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 316 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 317 | break; |
| 318 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 319 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 320 | case '(': |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 321 | case ')': |
| 322 | { |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 323 | lex->token.type = (BcLexToken) (c - '(' + BC_LEX_LEFT_PAREN); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 324 | break; |
| 325 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 326 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 327 | case '*': |
| 328 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 329 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 330 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 331 | lex->token.type = BC_LEX_OP_ASSIGN_MULTIPLY; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 332 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 333 | else lex->token.type = BC_LEX_OP_MULTIPLY; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 334 | break; |
| 335 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 336 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 337 | case '+': |
| 338 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 339 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 340 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 341 | lex->token.type = BC_LEX_OP_ASSIGN_PLUS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 342 | } |
| 343 | else if (c2 == '+') { |
| 344 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 345 | lex->token.type = BC_LEX_OP_INC; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 346 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 347 | else lex->token.type = BC_LEX_OP_PLUS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 348 | break; |
| 349 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 350 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 351 | case ',': |
| 352 | { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 353 | lex->token.type = BC_LEX_COMMA; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 354 | break; |
| 355 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 356 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 357 | case '-': |
| 358 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 359 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 360 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 361 | lex->token.type = BC_LEX_OP_ASSIGN_MINUS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 362 | } |
| 363 | else if (c2 == '-') { |
| 364 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 365 | lex->token.type = BC_LEX_OP_DEC; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 366 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 367 | else lex->token.type = BC_LEX_OP_MINUS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 368 | break; |
| 369 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 370 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 371 | case '.': |
| 372 | { |
Gavin Howard | 2a6e3a6 | 2018-03-05 10:03:20 -0700 | [diff] [blame] | 373 | c2 = lex->buffer[lex->idx]; |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 374 | if (isdigit(c2)) status = bc_lex_number(lex, c); |
Gavin Howard | 2a6e3a6 | 2018-03-05 10:03:20 -0700 | [diff] [blame] | 375 | else { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 376 | status = bc_posix_error(BC_STATUS_POSIX_DOT_LAST, |
| 377 | lex->file, lex->line, NULL); |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 378 | lex->token.type = BC_LEX_KEY_LAST; |
Gavin Howard | 2a6e3a6 | 2018-03-05 10:03:20 -0700 | [diff] [blame] | 379 | } |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 380 | break; |
| 381 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 382 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 383 | case '/': |
| 384 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 385 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 386 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 387 | lex->token.type = BC_LEX_OP_ASSIGN_DIVIDE; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 388 | } |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 389 | else if (c2 == '*') status = bc_lex_comment(lex); |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 390 | else lex->token.type = BC_LEX_OP_DIVIDE; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 391 | break; |
| 392 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 393 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 394 | case '0': |
| 395 | case '1': |
| 396 | case '2': |
| 397 | case '3': |
| 398 | case '4': |
| 399 | case '5': |
| 400 | case '6': |
| 401 | case '7': |
| 402 | case '8': |
| 403 | case '9': |
| 404 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 405 | status = bc_lex_number(lex, c); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 406 | break; |
| 407 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 408 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 409 | case ';': |
| 410 | { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 411 | lex->token.type = BC_LEX_SEMICOLON; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 412 | break; |
| 413 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 414 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 415 | case '<': |
| 416 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 417 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 418 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 419 | lex->token.type = BC_LEX_OP_REL_LESS_EQ; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 420 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 421 | else lex->token.type = BC_LEX_OP_REL_LESS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 422 | break; |
| 423 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 424 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 425 | case '=': |
| 426 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 427 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 428 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 429 | lex->token.type = BC_LEX_OP_REL_EQUAL; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 430 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 431 | else lex->token.type = BC_LEX_OP_ASSIGN; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 432 | break; |
| 433 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 434 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 435 | case '>': |
| 436 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 437 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 438 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 439 | lex->token.type = BC_LEX_OP_REL_GREATER_EQ; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 440 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 441 | else lex->token.type = BC_LEX_OP_REL_GREATER; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 442 | break; |
| 443 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 444 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 445 | case 'A': |
| 446 | case 'B': |
| 447 | case 'C': |
| 448 | case 'D': |
| 449 | case 'E': |
| 450 | case 'F': |
| 451 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 452 | status = bc_lex_number(lex, c); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 453 | break; |
| 454 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 455 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 456 | case '[': |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 457 | case ']': |
| 458 | { |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 459 | lex->token.type = (BcLexToken) (c - '[' + BC_LEX_LEFT_BRACKET); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 460 | break; |
| 461 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 462 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 463 | case '^': |
| 464 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 465 | if ((c2 = lex->buffer[lex->idx]) == '=') { |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 466 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 467 | lex->token.type = BC_LEX_OP_ASSIGN_POWER; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 468 | } |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 469 | else lex->token.type = BC_LEX_OP_POWER; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 470 | break; |
| 471 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 472 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 473 | case 'a': |
| 474 | case 'b': |
| 475 | case 'c': |
| 476 | case 'd': |
| 477 | case 'e': |
| 478 | case 'f': |
| 479 | case 'g': |
| 480 | case 'h': |
| 481 | case 'i': |
| 482 | case 'j': |
| 483 | case 'k': |
| 484 | case 'l': |
| 485 | case 'm': |
| 486 | case 'n': |
| 487 | case 'o': |
| 488 | case 'p': |
| 489 | case 'q': |
| 490 | case 'r': |
| 491 | case 's': |
| 492 | case 't': |
| 493 | case 'u': |
| 494 | case 'v': |
| 495 | case 'w': |
| 496 | case 'x': |
| 497 | case 'y': |
| 498 | case 'z': |
| 499 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 500 | status = bc_lex_name(lex); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 501 | break; |
| 502 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 503 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 504 | case '{': |
Gavin Howard | c312ab3 | 2018-03-29 15:47:10 -0600 | [diff] [blame] | 505 | case '}': |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 506 | { |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame^] | 507 | lex->token.type = (BcLexToken) (c - '{' + BC_LEX_LEFT_BRACE); |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 508 | break; |
| 509 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 510 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 511 | case '|': |
| 512 | { |
Gavin Howard | 45ff357 | 2018-05-15 16:33:58 -0600 | [diff] [blame] | 513 | if ((c2 = lex->buffer[lex->idx]) == '|') { |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 514 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 515 | if ((status = bc_posix_error(BC_STATUS_POSIX_BOOL_OPS, |
| 516 | lex->file, lex->line, "||"))) |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 517 | { |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 518 | return status; |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 519 | } |
| 520 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 521 | ++lex->idx; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 522 | lex->token.type = BC_LEX_OP_BOOL_OR; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 523 | } |
| 524 | else { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 525 | lex->token.type = BC_LEX_INVALID; |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 526 | status = BC_STATUS_LEX_BAD_CHARACTER; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 527 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 528 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 529 | break; |
| 530 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 531 | |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 532 | default: |
| 533 | { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 534 | lex->token.type = BC_LEX_INVALID; |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 535 | status = BC_STATUS_LEX_BAD_CHARACTER; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 536 | break; |
| 537 | } |
| 538 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 539 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 540 | return status; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 541 | } |
| 542 | |
Gavin Howard | 27fdfb9 | 2018-03-21 07:56:59 -0600 | [diff] [blame] | 543 | void bc_lex_init(BcLex *lex, const char *file) { |
| 544 | assert(lex && file); |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 545 | lex->line = 1; |
| 546 | lex->newline = false; |
| 547 | lex->file = file; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 548 | } |
| 549 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 550 | BcStatus bc_lex_next(BcLex *lex) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 551 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 552 | BcStatus status; |
Gavin Howard | fc71e24 | 2018-01-31 14:54:43 -0700 | [diff] [blame] | 553 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 554 | assert(lex); |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 555 | |
Gavin Howard | 0b190a0 | 2018-03-28 11:55:08 -0600 | [diff] [blame] | 556 | if (lex->token.type == BC_LEX_EOF) return BC_STATUS_LEX_EOF; |
| 557 | |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 558 | if (lex->idx == lex->len) { |
Gavin Howard | a58294c | 2018-03-24 14:07:28 -0600 | [diff] [blame] | 559 | lex->newline = true; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 560 | lex->token.type = BC_LEX_EOF; |
Gavin Howard | 0b190a0 | 2018-03-28 11:55:08 -0600 | [diff] [blame] | 561 | return BC_STATUS_SUCCESS; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 562 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 563 | |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 564 | if (lex->newline) { |
| 565 | ++lex->line; |
| 566 | lex->newline = false; |
Gavin Howard | 4bc73ee | 2018-01-26 11:39:20 -0700 | [diff] [blame] | 567 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 568 | |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 569 | // Loop until failure or we don't have whitespace. This |
| 570 | // is so the parser doesn't get inundated with whitespace. |
| 571 | do { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 572 | lex->token.string = NULL; |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 573 | status = bc_lex_token(lex); |
| 574 | } while (!status && lex->token.type == BC_LEX_WHITESPACE); |
Gavin Howard | 217a5d5 | 2018-01-31 12:23:07 -0700 | [diff] [blame] | 575 | |
Gavin Howard | c4c6753 | 2018-03-29 22:29:08 -0600 | [diff] [blame] | 576 | return status; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 577 | } |
Gavin Howard | 3575392 | 2018-03-21 19:22:08 -0600 | [diff] [blame] | 578 | |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 579 | BcStatus bc_lex_text(BcLex *lex, const char *text) { |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 580 | assert(lex && text); |
Gavin Howard | 3575392 | 2018-03-21 19:22:08 -0600 | [diff] [blame] | 581 | lex->buffer = text; |
| 582 | lex->idx = 0; |
| 583 | lex->len = strlen(text); |
Gavin Howard | 9f4d914 | 2018-03-28 12:21:34 -0600 | [diff] [blame] | 584 | lex->token.type = BC_LEX_INVALID; |
Gavin Howard | 68f2bae | 2018-03-26 13:02:27 -0600 | [diff] [blame] | 585 | return bc_lex_next(lex); |
Gavin Howard | 3575392 | 2018-03-21 19:22:08 -0600 | [diff] [blame] | 586 | } |