blob: dcace1e42f2c27bb2dc2f799b22a38c4f89d5684 [file] [log] [blame]
Gavin Howard5715b042018-02-12 16:11:42 -07001/*
Gavin Howardb5904bf2018-02-20 13:28:18 -07002 * *****************************************************************************
Gavin Howard5715b042018-02-12 16:11:42 -07003 *
Gavin Howardb5904bf2018-02-20 13:28:18 -07004 * Copyright 2018 Gavin D. Howard
Gavin Howard5715b042018-02-12 16:11:42 -07005 *
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 Howardb5904bf2018-02-20 13:28:18 -070017 * *****************************************************************************
Gavin Howard5715b042018-02-12 16:11:42 -070018 *
19 * The lexer.
20 *
21 */
22
Gavin Howard27fdfb92018-03-21 07:56:59 -060023#include <assert.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070024#include <ctype.h>
25#include <stdbool.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070026#include <string.h>
27
Gavin Howard29493062018-03-20 19:57:37 -060028#include <status.h>
Gavin Howard3ba6c8d2018-02-15 12:23:35 -070029#include <lex.h>
Gavin Howardd5551672018-09-22 19:52:42 -060030#include <vm.h>
Gavin Howard8a596d42018-01-15 15:46:01 -070031
Gavin Howard63738202018-09-26 15:34:20 -060032BcStatus bc_lex_comment(BcLex *l) {
Gavin Howard8a596d42018-01-15 15:46:01 -070033
Gavin Howard63738202018-09-26 15:34:20 -060034 size_t i, nls = 0;
35 const char *buf = l->buffer;
36 bool end = false;
Gavin Howard8a596d42018-01-15 15:46:01 -070037
Gavin Howard63738202018-09-26 15:34:20 -060038 l->t.t = BC_LEX_WHITESPACE;
Gavin Howard07732ec2018-02-27 15:40:02 -070039
Gavin Howard63738202018-09-26 15:34:20 -060040 for (i = ++l->idx; !end; i += !end) {
Gavin Howard07732ec2018-02-27 15:40:02 -070041
Gavin Howard63738202018-09-26 15:34:20 -060042 char c;
Gavin Howardf6e3fb32018-08-09 13:48:59 -060043
Gavin Howard63738202018-09-26 15:34:20 -060044 for (; (c = buf[i]) != '*' && c != '\0'; ++i) nls += (c == '\n');
Gavin Howard07732ec2018-02-27 15:40:02 -070045
Gavin Howard63738202018-09-26 15:34:20 -060046 if (c == '\0' || buf[i + 1] == '\0') {
47 l->idx = i;
48 return BC_STATUS_LEX_NO_COMMENT_END;
49 }
Gavin Howard07732ec2018-02-27 15:40:02 -070050
Gavin Howard63738202018-09-26 15:34:20 -060051 end = buf[i + 1] == '/';
52 }
Gavin Howard07732ec2018-02-27 15:40:02 -070053
Gavin Howard63738202018-09-26 15:34:20 -060054 l->idx = i + 2;
55 l->line += nls;
Gavin Howard8a596d42018-01-15 15:46:01 -070056
Gavin Howard63738202018-09-26 15:34:20 -060057 return BC_STATUS_SUCCESS;
Gavin Howard8a596d42018-01-15 15:46:01 -070058}
59
Gavin Howarded5c8312018-09-27 12:04:08 -060060void 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 Howard63738202018-09-26 15:34:20 -060066BcStatus bc_lex_number(BcLex *l, char start) {
Gavin Howard8a596d42018-01-15 15:46:01 -070067
Gavin Howard63738202018-09-26 15:34:20 -060068 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 Howardf2a40492018-03-05 11:27:29 -070073
Gavin Howard63738202018-09-26 15:34:20 -060074 last_pt = pt;
75 l->t.t = BC_LEX_NUMBER;
Gavin Howard07732ec2018-02-27 15:40:02 -070076
Gavin Howard63738202018-09-26 15:34:20 -060077 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 Howard07732ec2018-02-27 15:40:02 -070088
Gavin Howard63738202018-09-26 15:34:20 -060089 c = buf[++i];
90 }
Gavin Howard07732ec2018-02-27 15:40:02 -070091
Gavin Howard63738202018-09-26 15:34:20 -060092 len = i + 1 * !last_pt - bslashes * 2;
93 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
Gavin Howard07732ec2018-02-27 15:40:02 -070094
Gavin Howard63738202018-09-26 15:34:20 -060095 bc_vec_npop(&l->t.v, l->t.v.len);
Gavin Howard0275a552018-09-27 12:08:23 -060096 if ((s = bc_vec_expand(&l->t.v, len + 1))) return s;
Gavin Howard63738202018-09-26 15:34:20 -060097 if ((s = bc_vec_push(&l->t.v, 1, &start))) return s;
Gavin Howarda628aa22018-09-12 13:52:45 -060098
Gavin Howard63738202018-09-26 15:34:20 -060099 buf -= 1;
100 hits = 0;
Gavin Howard07732ec2018-02-27 15:40:02 -0700101
Gavin Howard63738202018-09-26 15:34:20 -0600102 for (j = 1; j < len + hits * 2; ++j) {
Gavin Howard07732ec2018-02-27 15:40:02 -0700103
Gavin Howard63738202018-09-26 15:34:20 -0600104 c = buf[j];
Gavin Howard07732ec2018-02-27 15:40:02 -0700105
Gavin Howard63738202018-09-26 15:34:20 -0600106 // 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 Howard07732ec2018-02-27 15:40:02 -0700113
Gavin Howard63738202018-09-26 15:34:20 -0600114 if ((s = bc_vec_push(&l->t.v, 1, &c))) return s;
115 }
Gavin Howard07732ec2018-02-27 15:40:02 -0700116
Gavin Howard63738202018-09-26 15:34:20 -0600117 if ((s = bc_vec_pushByte(&l->t.v, '\0'))) return s;
118 l->idx += i;
Gavin Howard8a596d42018-01-15 15:46:01 -0700119
Gavin Howard63738202018-09-26 15:34:20 -0600120 return BC_STATUS_SUCCESS;
Gavin Howard8a596d42018-01-15 15:46:01 -0700121}
122
Gavin Howard63738202018-09-26 15:34:20 -0600123BcStatus bc_lex_name(BcLex *l) {
Gavin Howard8a596d42018-01-15 15:46:01 -0700124
Gavin Howard63738202018-09-26 15:34:20 -0600125 BcStatus s;
126 size_t i;
127 char c;
128 const char *buf = l->buffer + l->idx - 1;
Gavin Howard8a596d42018-01-15 15:46:01 -0700129
Gavin Howard63738202018-09-26 15:34:20 -0600130 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
Gavin Howard07732ec2018-02-27 15:40:02 -0700131
Gavin Howard63738202018-09-26 15:34:20 -0600132 unsigned long len = (unsigned long) bc_lex_kws[i].len;
133 if (!strncmp(buf, bc_lex_kws[i].name, len)) {
Gavin Howard07732ec2018-02-27 15:40:02 -0700134
Gavin Howard63738202018-09-26 15:34:20 -0600135 l->t.t = BC_LEX_KEY_AUTO + (BcLexToken) i;
Gavin Howard07732ec2018-02-27 15:40:02 -0700136
Gavin Howard63738202018-09-26 15:34:20 -0600137 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 Howard07732ec2018-02-27 15:40:02 -0700143
Gavin Howard63738202018-09-26 15:34:20 -0600144 // We minus 1 because the index has already been incremented.
145 l->idx += len - 1;
Gavin Howard07732ec2018-02-27 15:40:02 -0700146
Gavin Howard63738202018-09-26 15:34:20 -0600147 return BC_STATUS_SUCCESS;
148 }
149 }
Gavin Howard8a596d42018-01-15 15:46:01 -0700150
Gavin Howard63738202018-09-26 15:34:20 -0600151 l->t.t = BC_LEX_NAME;
Gavin Howard07732ec2018-02-27 15:40:02 -0700152
Gavin Howard63738202018-09-26 15:34:20 -0600153 i = 0;
154 c = buf[i];
Gavin Howard07732ec2018-02-27 15:40:02 -0700155
Gavin Howard63738202018-09-26 15:34:20 -0600156 while ((c >= 'a' && c<= 'z') || (c >= '0' && c <= '9') || c == '_')
157 c = buf[++i];
Gavin Howard8a596d42018-01-15 15:46:01 -0700158
Gavin Howard63738202018-09-26 15:34:20 -0600159 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 Howard8a596d42018-01-15 15:46:01 -0700164
Gavin Howard63738202018-09-26 15:34:20 -0600165 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 Howard07732ec2018-02-27 15:40:02 -0700167
Gavin Howard63738202018-09-26 15:34:20 -0600168 // Increment the index. We minus 1 because it has already been incremented.
169 l->idx += i - 1;
Gavin Howard07732ec2018-02-27 15:40:02 -0700170
Gavin Howard63738202018-09-26 15:34:20 -0600171 return BC_STATUS_SUCCESS;
Gavin Howard8a596d42018-01-15 15:46:01 -0700172}
173
Gavin Howarded5c8312018-09-27 12:04:08 -0600174BcStatus bc_lex_init(BcLex *l, BcLexNext next) {
Gavin Howard63738202018-09-26 15:34:20 -0600175 assert(l);
Gavin Howarded5c8312018-09-27 12:04:08 -0600176 l->next = next;
Gavin Howard63738202018-09-26 15:34:20 -0600177 return bc_vec_init(&l->t.v, sizeof(uint8_t), NULL);
Gavin Howard69185042018-09-10 15:46:20 -0600178}
179
Gavin Howard63738202018-09-26 15:34:20 -0600180void bc_lex_free(BcLex *l) {
181 assert(l);
182 bc_vec_free(&l->t.v);
Gavin Howard69185042018-09-10 15:46:20 -0600183}
184
Gavin Howard63738202018-09-26 15:34:20 -0600185void 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 Howard8a596d42018-01-15 15:46:01 -0700190}
191
Gavin Howard63738202018-09-26 15:34:20 -0600192BcStatus 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 Howarded5c8312018-09-27 12:04:08 -0600198 return l->next(l);
Gavin Howard35753922018-03-21 19:22:08 -0600199}