xref: /freebsd-13-stable/sys/ddb/db_lex.c (revision 3bc80996974a61a4223eae4c1ccd47b6ee32a48a)
1 /*-
2  * SPDX-License-Identifier: MIT-CMU
3  *
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 /*
29  *	Author: David B. Golub, Carnegie Mellon University
30  *	Date:	7/90
31  */
32 /*
33  * Lexical analyzer.
34  */
35 
36 #include <sys/cdefs.h>
37 #include <sys/param.h>
38 #include <sys/libkern.h>
39 #include <sys/lock.h>
40 
41 #include <ddb/ddb.h>
42 #include <ddb/db_lex.h>
43 
44 static char	db_line[DB_MAXLINE];
45 static char *	db_lp, *db_endlp;
46 
47 static int	db_lex(int);
48 static void 	db_flush_line(void);
49 static int 	db_read_char(void);
50 static void 	db_unread_char(int);
51 
52 int
db_read_line(void)53 db_read_line(void)
54 {
55 	int	i;
56 
57 	i = db_readline(db_line, sizeof(db_line));
58 	if (i == 0)
59 	    return (0);	/* EOI */
60 	db_lp = db_line;
61 	db_endlp = db_lp + i;
62 	return (i);
63 }
64 
65 /*
66  * Simulate a line of input into DDB.
67  */
68 void
db_inject_line(const char * command)69 db_inject_line(const char *command)
70 {
71 
72 	strlcpy(db_line, command, sizeof(db_line));
73 	db_lp = db_line;
74 	db_endlp = db_lp + strlen(command);
75 }
76 
77 /*
78  * In rare cases, we may want to pull the remainder of the line input
79  * verbatim, rather than lexing it.  For example, when assigning literal
80  * values associated with scripts.  In that case, return a static pointer to
81  * the current location in the input buffer.  The caller must be aware that
82  * the contents are not stable if other lex/input calls are made.
83  */
84 char *
db_get_line(void)85 db_get_line(void)
86 {
87 
88 	return (db_lp);
89 }
90 
91 static void
db_flush_line(void)92 db_flush_line(void)
93 {
94 	db_lp = db_line;
95 	db_endlp = db_line;
96 }
97 
98 static int	db_look_char = 0;
99 
100 static int
db_read_char(void)101 db_read_char(void)
102 {
103 	int	c;
104 
105 	if (db_look_char != 0) {
106 	    c = db_look_char;
107 	    db_look_char = 0;
108 	}
109 	else if (db_lp >= db_endlp)
110 	    c = -1;
111 	else
112 	    c = *db_lp++;
113 	return (c);
114 }
115 
116 static void
db_unread_char(c)117 db_unread_char(c)
118 	int c;
119 {
120 	db_look_char = c;
121 }
122 
123 static int	db_look_token = 0;
124 
125 void
db_unread_token(int t)126 db_unread_token(int t)
127 {
128 	db_look_token = t;
129 }
130 
131 int
db_read_token_flags(int flags)132 db_read_token_flags(int flags)
133 {
134 	int	t;
135 
136 	MPASS((flags & ~(DRT_VALID_FLAGS_MASK)) == 0);
137 
138 	if (db_look_token) {
139 	    t = db_look_token;
140 	    db_look_token = 0;
141 	}
142 	else
143 	    t = db_lex(flags);
144 	return (t);
145 }
146 
147 db_expr_t	db_tok_number;
148 char	db_tok_string[TOK_STRING_SIZE];
149 
150 db_expr_t	db_radix = 16;
151 
152 void
db_flush_lex(void)153 db_flush_lex(void)
154 {
155 	db_flush_line();
156 	db_look_char = 0;
157 	db_look_token = 0;
158 }
159 
160 static int
db_lex(int flags)161 db_lex(int flags)
162 {
163 	int	c, n, radix_mode;
164 	bool	lex_wspace, lex_hex_numbers;
165 
166 	switch (flags & DRT_RADIX_MASK) {
167 	case DRT_DEFAULT_RADIX:
168 		radix_mode = -1;
169 		break;
170 	case DRT_OCTAL:
171 		radix_mode = 8;
172 		break;
173 	case DRT_DECIMAL:
174 		radix_mode = 10;
175 		break;
176 	case DRT_HEXADECIMAL:
177 		radix_mode = 16;
178 		break;
179 	}
180 
181 	lex_wspace = ((flags & DRT_WSPACE) != 0);
182 	lex_hex_numbers = ((flags & DRT_HEX) != 0);
183 
184 	c = db_read_char();
185 	for (n = 0; c <= ' ' || c > '~'; n++) {
186 	    if (c == '\n' || c == -1)
187 		return (tEOL);
188 	    c = db_read_char();
189 	}
190 	if (lex_wspace && n != 0) {
191 	    db_unread_char(c);
192 	    return (tWSPACE);
193 	}
194 
195 	if ((c >= '0' && c <= '9') ||
196 	   (lex_hex_numbers &&
197 	   ((c >= 'a' && c <= 'f') ||
198 	   (c >= 'A' && c <= 'F')))) {
199 	    /* number */
200 	    int	r, digit = 0;
201 
202 	    if (radix_mode != -1)
203 		r = radix_mode;
204 	    else if (c != '0')
205 		r = db_radix;
206 	    else {
207 		c = db_read_char();
208 		if (c == 'O' || c == 'o')
209 		    r = 8;
210 		else if (c == 'T' || c == 't')
211 		    r = 10;
212 		else if (c == 'X' || c == 'x')
213 		    r = 16;
214 		else {
215 		    r = db_radix;
216 		    db_unread_char(c);
217 		}
218 		c = db_read_char();
219 	    }
220 	    db_tok_number = 0;
221 	    for (;;) {
222 		if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
223 		    digit = c - '0';
224 		else if (r == 16 && ((c >= 'A' && c <= 'F') ||
225 				     (c >= 'a' && c <= 'f'))) {
226 		    if (c >= 'a')
227 			digit = c - 'a' + 10;
228 		    else if (c >= 'A')
229 			digit = c - 'A' + 10;
230 		}
231 		else
232 		    break;
233 		db_tok_number = db_tok_number * r + digit;
234 		c = db_read_char();
235 	    }
236 	    if ((c >= '0' && c <= '9') ||
237 		(c >= 'A' && c <= 'Z') ||
238 		(c >= 'a' && c <= 'z') ||
239 		(c == '_'))
240 	    {
241 		db_error("Bad character in number\n");
242 		db_flush_lex();
243 		return (tEOF);
244 	    }
245 	    db_unread_char(c);
246 	    return (tNUMBER);
247 	}
248 	if ((c >= 'A' && c <= 'Z') ||
249 	    (c >= 'a' && c <= 'z') ||
250 	    c == '_' || c == '\\')
251 	{
252 	    /* string */
253 	    char *cp;
254 
255 	    cp = db_tok_string;
256 	    if (c == '\\') {
257 		c = db_read_char();
258 		if (c == '\n' || c == -1)
259 		    db_error("Bad escape\n");
260 	    }
261 	    *cp++ = c;
262 	    while (1) {
263 		c = db_read_char();
264 		if ((c >= 'A' && c <= 'Z') ||
265 		    (c >= 'a' && c <= 'z') ||
266 		    (c >= '0' && c <= '9') ||
267 		    c == '_' || c == '\\' || c == ':' || c == '.')
268 		{
269 		    if (c == '\\') {
270 			c = db_read_char();
271 			if (c == '\n' || c == -1)
272 			    db_error("Bad escape\n");
273 		    }
274 		    *cp++ = c;
275 		    if (cp == db_tok_string+sizeof(db_tok_string)) {
276 			db_error("String too long\n");
277 			db_flush_lex();
278 			return (tEOF);
279 		    }
280 		    continue;
281 		}
282 		else {
283 		    *cp = '\0';
284 		    break;
285 		}
286 	    }
287 	    db_unread_char(c);
288 	    return (tIDENT);
289 	}
290 
291 	switch (c) {
292 	    case '+':
293 		return (tPLUS);
294 	    case '-':
295 		return (tMINUS);
296 	    case '.':
297 		c = db_read_char();
298 		if (c == '.')
299 		    return (tDOTDOT);
300 		db_unread_char(c);
301 		return (tDOT);
302 	    case '*':
303 		return (tSTAR);
304 	    case '/':
305 		return (tSLASH);
306 	    case '=':
307 		c = db_read_char();
308 		if (c == '=')
309 		    return (tLOG_EQ);
310 		db_unread_char(c);
311 		return (tEQ);
312 	    case '%':
313 		return (tPCT);
314 	    case '#':
315 		return (tHASH);
316 	    case '(':
317 		return (tLPAREN);
318 	    case ')':
319 		return (tRPAREN);
320 	    case ',':
321 		return (tCOMMA);
322 	    case '"':
323 		return (tDITTO);
324 	    case '$':
325 		return (tDOLLAR);
326 	    case '!':
327 		c = db_read_char();
328 		if (c == '='){
329 			return (tLOG_NOT_EQ);
330 		}
331 		db_unread_char(c);
332 		return (tEXCL);
333 	    case ':':
334 		c = db_read_char();
335 		if (c == ':')
336 			return (tCOLONCOLON);
337 		db_unread_char(c);
338 		return (tCOLON);
339 	    case ';':
340 		return (tSEMI);
341 	    case '&':
342 		c = db_read_char();
343 		if (c == '&')
344 		    return (tLOG_AND);
345 		db_unread_char(c);
346 		return (tBIT_AND);
347 	    case '|':
348 		c = db_read_char();
349 		if (c == '|')
350 		    return (tLOG_OR);
351 		db_unread_char(c);
352 		return (tBIT_OR);
353 	    case '<':
354 		c = db_read_char();
355 		if (c == '<')
356 		    return (tSHIFT_L);
357 		if (c == '=')
358 		    return (tLESS_EQ);
359 		db_unread_char(c);
360 		return (tLESS);
361 	    case '>':
362 		c = db_read_char();
363 		if (c == '>')
364 		    return (tSHIFT_R);
365 		if (c == '=')
366 		    return (tGREATER_EQ);
367 		db_unread_char(c);
368 		return (tGREATER);
369 	    case '?':
370 		return (tQUESTION);
371 	    case '~':
372 		return (tBIT_NOT);
373 	    case -1:
374 		return (tEOF);
375 	}
376 	db_printf("Bad character\n");
377 	db_flush_lex();
378 	return (tEOF);
379 }
380