xref: /freebsd/contrib/bc/src/dc_lex.c (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2020 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 
43 bool dc_lex_negCommand(BcLex *l) {
44 	char c = l->buf[l->i];
45 	return !BC_LEX_NUM_CHAR(c, false, false);
46 }
47 
48 static 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_npop(&l->str, l->str.len);
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 
71 static 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_npop(&l->str, l->str.len);
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 
106 void 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