• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * *****************************************************************************
3  *
4  * Copyright (c) 2018-2019 Gavin D. Howard and contributors.
5  *
6  * All rights reserved.
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 <status.h>
41 #include <lex.h>
42 #include <dc.h>
43 #include <vm.h>
44 
dc_lex_negCommand(BcLex * l)45 bool dc_lex_negCommand(BcLex *l) {
46 	char c = l->buf[l->i];
47 	return !BC_LEX_NUM_CHAR(c, false, false);
48 }
49 
dc_lex_register(BcLex * l)50 static BcStatus dc_lex_register(BcLex *l) {
51 
52 	if (DC_X && isspace(l->buf[l->i - 1])) {
53 
54 		char c;
55 
56 		bc_lex_whitespace(l);
57 		c = l->buf[l->i];
58 
59 		if (!isalnum(c) && c != '_')
60 			return bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c);
61 
62 		l->i += 1;
63 		bc_lex_name(l);
64 	}
65 	else {
66 		bc_vec_npop(&l->str, l->str.len);
67 		bc_vec_pushByte(&l->str, (uchar) l->buf[l->i - 1]);
68 		bc_vec_pushByte(&l->str, '\0');
69 		l->t = BC_LEX_NAME;
70 	}
71 
72 	return BC_STATUS_SUCCESS;
73 }
74 
dc_lex_string(BcLex * l)75 static BcStatus dc_lex_string(BcLex *l) {
76 
77 	size_t depth = 1, nls = 0, i = l->i;
78 	char c;
79 
80 	l->t = BC_LEX_STR;
81 	bc_vec_npop(&l->str, l->str.len);
82 
83 	for (; (c = l->buf[i]) && depth; ++i) {
84 
85 		if (c == '\\') {
86 			c = l->buf[++i];
87 			if (!c) break;
88 		}
89 		else {
90 			depth += (c == '[');
91 			depth -= (c == ']');
92 		}
93 
94 		nls += (c == '\n');
95 
96 		if (depth) bc_vec_push(&l->str, &c);
97 	}
98 
99 	if (BC_ERR(c == '\0' && depth)) {
100 		l->i = i;
101 		return bc_lex_err(l, BC_ERROR_PARSE_STRING);
102 	}
103 
104 	bc_vec_pushByte(&l->str, '\0');
105 
106 	l->i = i;
107 	l->line += nls;
108 
109 	return BC_STATUS_SUCCESS;
110 }
111 
dc_lex_token(BcLex * l)112 BcStatus dc_lex_token(BcLex *l) {
113 
114 	BcStatus s = BC_STATUS_SUCCESS;
115 	char c = l->buf[l->i++], c2;
116 	size_t i;
117 
118 	for (i = 0; i < dc_lex_regs_len; ++i) {
119 		if (l->last == dc_lex_regs[i]) return dc_lex_register(l);
120 	}
121 
122 	if (c >= '$' && c <= '~' &&
123 	    (l->t = dc_lex_tokens[(c - '$')]) != BC_LEX_INVALID)
124 	{
125 		return s;
126 	}
127 
128 	// This is the workhorse of the lexer.
129 	switch (c) {
130 
131 		case '\0':
132 		case '\n':
133 		case '\t':
134 		case '\v':
135 		case '\f':
136 		case '\r':
137 		case ' ':
138 		{
139 			bc_lex_commonTokens(l, c);
140 			break;
141 		}
142 
143 		case '!':
144 		{
145 			c2 = l->buf[l->i];
146 
147 			if (c2 == '=') l->t = BC_LEX_OP_REL_NE;
148 			else if (c2 == '<') l->t = BC_LEX_OP_REL_LE;
149 			else if (c2 == '>') l->t = BC_LEX_OP_REL_GE;
150 			else return bc_lex_invalidChar(l, c);
151 
152 			l->i += 1;
153 			break;
154 		}
155 
156 		case '#':
157 		{
158 			bc_lex_lineComment(l);
159 			break;
160 		}
161 
162 		case '.':
163 		{
164 			c2 = l->buf[l->i];
165 			if (BC_NO_ERR(BC_LEX_NUM_CHAR(c2, true, false)))
166 				s = bc_lex_number(l, c);
167 			else s = bc_lex_invalidChar(l, c);
168 			break;
169 		}
170 
171 		case '0':
172 		case '1':
173 		case '2':
174 		case '3':
175 		case '4':
176 		case '5':
177 		case '6':
178 		case '7':
179 		case '8':
180 		case '9':
181 		case 'A':
182 		case 'B':
183 		case 'C':
184 		case 'D':
185 		case 'E':
186 		case 'F':
187 		{
188 			s = bc_lex_number(l, c);
189 			break;
190 		}
191 
192 		case '[':
193 		{
194 			s = dc_lex_string(l);
195 			break;
196 		}
197 
198 		default:
199 		{
200 			s = bc_lex_invalidChar(l, c);
201 			break;
202 		}
203 	}
204 
205 	return s;
206 }
207 #endif // DC_ENABLED
208