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
43bool dc_lex_negCommand(BcLex *l) {
44	char c = l->buf[l->i];
45	return !BC_LEX_NUM_CHAR(c, false, false);
46}
47
48static 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
71static 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
106void 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