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> |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 26 | #include <string.h> |
| 27 | |
Gavin Howard | 2949306 | 2018-03-20 19:57:37 -0600 | [diff] [blame] | 28 | #include <status.h> |
Gavin Howard | 3ba6c8d | 2018-02-15 12:23:35 -0700 | [diff] [blame] | 29 | #include <lex.h> |
Gavin Howard | d555167 | 2018-09-22 19:52:42 -0600 | [diff] [blame] | 30 | #include <vm.h> |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 31 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 32 | BcStatus bc_lex_comment(BcLex *l) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 33 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 34 | size_t i, nls = 0; |
| 35 | const char *buf = l->buffer; |
| 36 | bool end = false; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 37 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 38 | l->t.t = BC_LEX_WHITESPACE; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 39 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 40 | for (i = ++l->idx; !end; i += !end) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 41 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 42 | char c; |
Gavin Howard | f6e3fb3 | 2018-08-09 13:48:59 -0600 | [diff] [blame] | 43 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 44 | for (; (c = buf[i]) != '*' && c != '\0'; ++i) nls += (c == '\n'); |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 45 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 46 | if (c == '\0' || buf[i + 1] == '\0') { |
| 47 | l->idx = i; |
| 48 | return BC_STATUS_LEX_NO_COMMENT_END; |
| 49 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 50 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 51 | end = buf[i + 1] == '/'; |
| 52 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 53 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 54 | l->idx = i + 2; |
| 55 | l->line += nls; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 56 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 57 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 58 | } |
| 59 | |
Gavin Howard | ed5c831 | 2018-09-27 12:04:08 -0600 | [diff] [blame] | 60 | void bc_lex_lineComment(BcLex *l) { |
| 61 | l->t.t = BC_LEX_WHITESPACE; |
| 62 | while (l->idx < l->len && l->buffer[l->idx++] != '\n'); |
| 63 | --l->idx; |
| 64 | } |
| 65 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 66 | BcStatus bc_lex_number(BcLex *l, char start) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 67 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 68 | BcStatus s; |
| 69 | const char *buf = l->buffer + l->idx; |
| 70 | size_t len, hits, bslashes = 0, i = 0, j; |
| 71 | char c = buf[i]; |
| 72 | bool last_pt, pt = start == '.'; |
Gavin Howard | f2a4049 | 2018-03-05 11:27:29 -0700 | [diff] [blame] | 73 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 74 | last_pt = pt; |
| 75 | l->t.t = BC_LEX_NUMBER; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 76 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 77 | while (c && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || |
| 78 | (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n'))) |
| 79 | { |
| 80 | if (c != '\\') { |
| 81 | last_pt = c == '.'; |
| 82 | pt = pt || last_pt; |
| 83 | } |
| 84 | else { |
| 85 | ++i; |
| 86 | bslashes += 1; |
| 87 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 88 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 89 | c = buf[++i]; |
| 90 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 91 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 92 | len = i + 1 * !last_pt - bslashes * 2; |
| 93 | if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 94 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 95 | bc_vec_npop(&l->t.v, l->t.v.len); |
Gavin Howard | 0275a55 | 2018-09-27 12:08:23 -0600 | [diff] [blame^] | 96 | if ((s = bc_vec_expand(&l->t.v, len + 1))) return s; |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 97 | if ((s = bc_vec_push(&l->t.v, 1, &start))) return s; |
Gavin Howard | a628aa2 | 2018-09-12 13:52:45 -0600 | [diff] [blame] | 98 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 99 | buf -= 1; |
| 100 | hits = 0; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 101 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 102 | for (j = 1; j < len + hits * 2; ++j) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 103 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 104 | c = buf[j]; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 105 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 106 | // If we have hit a backslash, skip it. We don't have |
| 107 | // to check for a newline because it's guaranteed. |
| 108 | if (hits < bslashes && c == '\\') { |
| 109 | ++hits; |
| 110 | ++j; |
| 111 | continue; |
| 112 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 113 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 114 | if ((s = bc_vec_push(&l->t.v, 1, &c))) return s; |
| 115 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 116 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 117 | if ((s = bc_vec_pushByte(&l->t.v, '\0'))) return s; |
| 118 | l->idx += i; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 119 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 120 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 121 | } |
| 122 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 123 | BcStatus bc_lex_name(BcLex *l) { |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 124 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 125 | BcStatus s; |
| 126 | size_t i; |
| 127 | char c; |
| 128 | const char *buf = l->buffer + l->idx - 1; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 129 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 130 | for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 131 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 132 | unsigned long len = (unsigned long) bc_lex_kws[i].len; |
| 133 | if (!strncmp(buf, bc_lex_kws[i].name, len)) { |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 134 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 135 | l->t.t = BC_LEX_KEY_AUTO + (BcLexToken) i; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 136 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 137 | if (!bc_lex_kws[i].posix && |
| 138 | (s = bc_vm_posix_error(BC_STATUS_POSIX_BAD_KEYWORD, l->file, |
| 139 | l->line, bc_lex_kws[i].name))) |
| 140 | { |
| 141 | return s; |
| 142 | } |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 143 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 144 | // We minus 1 because the index has already been incremented. |
| 145 | l->idx += len - 1; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 146 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 147 | return BC_STATUS_SUCCESS; |
| 148 | } |
| 149 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 150 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 151 | l->t.t = BC_LEX_NAME; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 152 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 153 | i = 0; |
| 154 | c = buf[i]; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 155 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 156 | while ((c >= 'a' && c<= 'z') || (c >= '0' && c <= '9') || c == '_') |
| 157 | c = buf[++i]; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 158 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 159 | if (i > 1 && (s = bc_vm_posix_error(BC_STATUS_POSIX_NAME_LEN, |
| 160 | l->file, l->line, buf))) |
| 161 | { |
| 162 | return s; |
| 163 | } |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 164 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 165 | if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN; |
| 166 | if ((s = bc_vec_string(&l->t.v, i, buf))) return s; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 167 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 168 | // Increment the index. We minus 1 because it has already been incremented. |
| 169 | l->idx += i - 1; |
Gavin Howard | 07732ec | 2018-02-27 15:40:02 -0700 | [diff] [blame] | 170 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 171 | return BC_STATUS_SUCCESS; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 172 | } |
| 173 | |
Gavin Howard | ed5c831 | 2018-09-27 12:04:08 -0600 | [diff] [blame] | 174 | BcStatus bc_lex_init(BcLex *l, BcLexNext next) { |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 175 | assert(l); |
Gavin Howard | ed5c831 | 2018-09-27 12:04:08 -0600 | [diff] [blame] | 176 | l->next = next; |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 177 | return bc_vec_init(&l->t.v, sizeof(uint8_t), NULL); |
Gavin Howard | 6918504 | 2018-09-10 15:46:20 -0600 | [diff] [blame] | 178 | } |
| 179 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 180 | void bc_lex_free(BcLex *l) { |
| 181 | assert(l); |
| 182 | bc_vec_free(&l->t.v); |
Gavin Howard | 6918504 | 2018-09-10 15:46:20 -0600 | [diff] [blame] | 183 | } |
| 184 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 185 | void bc_lex_file(BcLex *l, const char *file) { |
| 186 | assert(l && file); |
| 187 | l->line = 1; |
| 188 | l->newline = false; |
| 189 | l->file = file; |
Gavin Howard | 8a596d4 | 2018-01-15 15:46:01 -0700 | [diff] [blame] | 190 | } |
| 191 | |
Gavin Howard | 6373820 | 2018-09-26 15:34:20 -0600 | [diff] [blame] | 192 | BcStatus bc_lex_text(BcLex *l, const char *text) { |
| 193 | assert(l && text); |
| 194 | l->buffer = text; |
| 195 | l->idx = 0; |
| 196 | l->len = strlen(text); |
| 197 | l->t.t = BC_LEX_INVALID; |
Gavin Howard | ed5c831 | 2018-09-27 12:04:08 -0600 | [diff] [blame] | 198 | return l->next(l); |
Gavin Howard | 3575392 | 2018-03-21 19:22:08 -0600 | [diff] [blame] | 199 | } |