blob: 16c35e6ba3dfe3a14041dd54434969c4cd0e3836 [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 *
Gavin Howardd2a05252018-09-27 14:00:40 -060019 * Common code for the lexers.
Gavin Howard5715b042018-02-12 16:11:42 -070020 *
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 Howarded5c8312018-09-27 12:04:08 -060032void bc_lex_lineComment(BcLex *l) {
33 l->t.t = BC_LEX_WHITESPACE;
34 while (l->idx < l->len && l->buffer[l->idx++] != '\n');
35 --l->idx;
36}
37
Gavin Howard364df3b2018-09-28 09:48:19 -060038void bc_lex_whitespace(BcLex *l) {
39 char c;
40 l->t.t = BC_LEX_WHITESPACE;
41 for (; (c = l->buffer[l->idx]) != '\n' && isspace(c); ++l->idx);
42}
43
Gavin Howard63738202018-09-26 15:34:20 -060044BcStatus bc_lex_number(BcLex *l, char start) {
Gavin Howard8a596d42018-01-15 15:46:01 -070045
Gavin Howard63738202018-09-26 15:34:20 -060046 BcStatus s;
47 const char *buf = l->buffer + l->idx;
48 size_t len, hits, bslashes = 0, i = 0, j;
49 char c = buf[i];
50 bool last_pt, pt = start == '.';
Gavin Howardf2a40492018-03-05 11:27:29 -070051
Gavin Howard63738202018-09-26 15:34:20 -060052 last_pt = pt;
53 l->t.t = BC_LEX_NUMBER;
Gavin Howard07732ec2018-02-27 15:40:02 -070054
Gavin Howard63738202018-09-26 15:34:20 -060055 while (c && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
56 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
57 {
58 if (c != '\\') {
59 last_pt = c == '.';
60 pt = pt || last_pt;
61 }
62 else {
63 ++i;
64 bslashes += 1;
65 }
Gavin Howard07732ec2018-02-27 15:40:02 -070066
Gavin Howard63738202018-09-26 15:34:20 -060067 c = buf[++i];
68 }
Gavin Howard07732ec2018-02-27 15:40:02 -070069
Gavin Howard63738202018-09-26 15:34:20 -060070 len = i + 1 * !last_pt - bslashes * 2;
71 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
Gavin Howard07732ec2018-02-27 15:40:02 -070072
Gavin Howard63738202018-09-26 15:34:20 -060073 bc_vec_npop(&l->t.v, l->t.v.len);
Gavin Howard0275a552018-09-27 12:08:23 -060074 if ((s = bc_vec_expand(&l->t.v, len + 1))) return s;
Gavin Howard63738202018-09-26 15:34:20 -060075 if ((s = bc_vec_push(&l->t.v, 1, &start))) return s;
Gavin Howarda628aa22018-09-12 13:52:45 -060076
Gavin Howard63738202018-09-26 15:34:20 -060077 buf -= 1;
78 hits = 0;
Gavin Howard07732ec2018-02-27 15:40:02 -070079
Gavin Howard63738202018-09-26 15:34:20 -060080 for (j = 1; j < len + hits * 2; ++j) {
Gavin Howard07732ec2018-02-27 15:40:02 -070081
Gavin Howard63738202018-09-26 15:34:20 -060082 c = buf[j];
Gavin Howard07732ec2018-02-27 15:40:02 -070083
Gavin Howard63738202018-09-26 15:34:20 -060084 // If we have hit a backslash, skip it. We don't have
85 // to check for a newline because it's guaranteed.
86 if (hits < bslashes && c == '\\') {
87 ++hits;
88 ++j;
89 continue;
90 }
Gavin Howard07732ec2018-02-27 15:40:02 -070091
Gavin Howard63738202018-09-26 15:34:20 -060092 if ((s = bc_vec_push(&l->t.v, 1, &c))) return s;
93 }
Gavin Howard07732ec2018-02-27 15:40:02 -070094
Gavin Howard63738202018-09-26 15:34:20 -060095 if ((s = bc_vec_pushByte(&l->t.v, '\0'))) return s;
96 l->idx += i;
Gavin Howard8a596d42018-01-15 15:46:01 -070097
Gavin Howard63738202018-09-26 15:34:20 -060098 return BC_STATUS_SUCCESS;
Gavin Howard8a596d42018-01-15 15:46:01 -070099}
100
Gavin Howarded5c8312018-09-27 12:04:08 -0600101BcStatus bc_lex_init(BcLex *l, BcLexNext next) {
Gavin Howard63738202018-09-26 15:34:20 -0600102 assert(l);
Gavin Howarded5c8312018-09-27 12:04:08 -0600103 l->next = next;
Gavin Howard63738202018-09-26 15:34:20 -0600104 return bc_vec_init(&l->t.v, sizeof(uint8_t), NULL);
Gavin Howard69185042018-09-10 15:46:20 -0600105}
106
Gavin Howard63738202018-09-26 15:34:20 -0600107void bc_lex_free(BcLex *l) {
108 assert(l);
109 bc_vec_free(&l->t.v);
Gavin Howard69185042018-09-10 15:46:20 -0600110}
111
Gavin Howard63738202018-09-26 15:34:20 -0600112void bc_lex_file(BcLex *l, const char *file) {
113 assert(l && file);
114 l->line = 1;
115 l->newline = false;
116 l->file = file;
Gavin Howard8a596d42018-01-15 15:46:01 -0700117}
118
Gavin Howard63738202018-09-26 15:34:20 -0600119BcStatus bc_lex_text(BcLex *l, const char *text) {
120 assert(l && text);
121 l->buffer = text;
122 l->idx = 0;
123 l->len = strlen(text);
124 l->t.t = BC_LEX_INVALID;
Gavin Howard364df3b2018-09-28 09:48:19 -0600125 return bc_lex_next(l);
126}
127
128BcStatus bc_lex_next(BcLex *l) {
129
130 BcStatus s;
131
132 assert(l);
133
134 if (l->t.t == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
135
136 if (l->idx == l->len) {
137 l->newline = true;
138 l->t.t = BC_LEX_EOF;
139 return BC_STATUS_SUCCESS;
140 }
141
142 if (l->newline) {
143 ++l->line;
144 l->newline = false;
145 }
146
147 // Loop until failure or we don't have whitespace. This
148 // is so the parser doesn't get inundated with whitespace.
149 do {
150 s = l->next(l);
151 } while (!s && l->t.t == BC_LEX_WHITESPACE);
152
153 return s;
Gavin Howard35753922018-03-21 19:22:08 -0600154}