xref: /netbsd-src/sys/ddb/db_lex.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: db_lex.c,v 1.20 2005/11/27 13:05:28 yamt Exp $	*/
2 
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 "AS IS"
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  *	Author: David B. Golub, Carnegie Mellon University
29  *	Date:	7/90
30  */
31 
32 /*
33  * Lexical analyzer.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: db_lex.c,v 1.20 2005/11/27 13:05:28 yamt Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 
42 #include <machine/db_machdep.h>
43 
44 #include <ddb/db_lex.h>
45 #include <ddb/db_output.h>
46 #include <ddb/db_command.h>
47 #include <ddb/db_sym.h>
48 #include <ddb/db_extern.h>
49 #include <ddb/db_interface.h>
50 
51 db_expr_t	db_tok_number;
52 char		db_tok_string[TOK_STRING_SIZE];
53 
54 static char	db_line[DB_LINE_MAXLEN];
55 static const char *db_lp;
56 static const char *db_endlp;
57 
58 static int	db_look_char = 0;
59 static int	db_look_token = 0;
60 
61 static void	db_flush_line(void);
62 static int	db_read_char(void);
63 static void	db_unread_char(int);
64 static int	db_lex(void);
65 
66 int
67 db_read_line(void)
68 {
69 	int	i;
70 
71 	i = db_readline(db_line, sizeof(db_line));
72 	if (i == 0)
73 		return (0);	/* EOI */
74 	db_set_line(db_line, db_line + i);
75 	return (i);
76 }
77 
78 void
79 db_set_line(const char *sp, const char *ep)
80 {
81 
82 	db_lp = sp;
83 	db_endlp = ep;
84 }
85 
86 static void
87 db_flush_line(void)
88 {
89 
90 	db_lp = db_line;
91 	db_endlp = db_line;
92 }
93 
94 static int
95 db_read_char(void)
96 {
97 	int	c;
98 
99 	if (db_look_char != 0) {
100 		c = db_look_char;
101 		db_look_char = 0;
102 	}
103 	else if (db_lp >= db_endlp)
104 		c = -1;
105 	else
106 		c = *db_lp++;
107 	return (c);
108 }
109 
110 static void
111 db_unread_char(int c)
112 {
113 
114 	db_look_char = c;
115 }
116 
117 void
118 db_unread_token(int t)
119 {
120 
121 	db_look_token = t;
122 }
123 
124 int
125 db_read_token(void)
126 {
127 	int	t;
128 
129 	if (db_look_token) {
130 		t = db_look_token;
131 		db_look_token = 0;
132 	}
133 	else
134 		t = db_lex();
135 	return (t);
136 }
137 
138 int	db_radix = 16;
139 
140 /*
141  * Convert the number to a string in the current radix.
142  * This replaces the non-standard %n printf() format.
143  */
144 
145 char *
146 db_num_to_str(db_expr_t val)
147 {
148 
149 	/*
150 	 * 2 chars for "0x", 1 for a sign ("-")
151 	 * up to 21 chars for a 64-bit number:
152 	 *   % echo 2^64 | bc | wc -c
153 	 *   21
154 	 * and 1 char for a terminal NUL
155 	 * 2+1+21+1 => 25
156 	 */
157 	static char buf[25];
158 
159 	if (db_radix == 16)
160 		snprintf(buf, sizeof(buf), DB_EXPR_T_IS_QUAD ? "%#qx" : "%#lx",
161 		    val);
162 	else if (db_radix == 8)
163 		snprintf(buf, sizeof(buf), DB_EXPR_T_IS_QUAD ? "%#qo" : "%#lo",
164 		    val);
165 	else
166 		snprintf(buf, sizeof(buf), DB_EXPR_T_IS_QUAD ? "%qu" : "%lu",
167 		    val);
168 
169 	return (buf);
170 }
171 
172 void
173 db_flush_lex(void)
174 {
175 
176 	db_flush_line();
177 	db_look_char = 0;
178 	db_look_token = 0;
179 }
180 
181 static int
182 db_lex(void)
183 {
184 	int	c;
185 
186 	c = db_read_char();
187 	while (c <= ' ' || c > '~') {
188 		if (c == '\n' || c == -1)
189 			return (tEOL);
190 		c = db_read_char();
191 	}
192 
193 	if (c >= '0' && c <= '9') {
194 		/* number */
195 		db_expr_t	r, digit = 0;
196 
197 		if (c > '0')
198 			r = db_radix;
199 		else {
200 			c = db_read_char();
201 			if (c == 'O' || c == 'o')
202 				r = 8;
203 			else if (c == 'T' || c == 't')
204 				r = 10;
205 			else if (c == 'X' || c == 'x')
206 				r = 16;
207 			else {
208 				r = db_radix;
209 				db_unread_char(c);
210 			}
211 			c = db_read_char();
212 		}
213 		db_tok_number = 0;
214 		for (;;) {
215 			if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
216 				digit = c - '0';
217 			else if (r == 16 && ((c >= 'A' && c <= 'F') ||
218 				(c >= 'a' && c <= 'f'))) {
219 				if (c >= 'a')
220 					digit = c - 'a' + 10;
221 				else if (c >= 'A')
222 					digit = c - 'A' + 10;
223 			}
224 			else
225 				break;
226 			db_tok_number = db_tok_number * r + digit;
227 			c = db_read_char();
228 		}
229 		if ((c >= '0' && c <= '9') ||
230 		    (c >= 'A' && c <= 'Z') ||
231 		    (c >= 'a' && c <= 'z') ||
232 		    (c == '_')) {
233 			db_error("Bad character in number\n");
234 			/*NOTREACHED*/
235 		}
236 		db_unread_char(c);
237 		return (tNUMBER);
238 	}
239 	if ((c >= 'A' && c <= 'Z') ||
240 	    (c >= 'a' && c <= 'z') ||
241 	    c == '_' || c == '\\') {
242 		/* string */
243 		char *cp;
244 
245 		cp = db_tok_string;
246 		if (c == '\\') {
247 			c = db_read_char();
248 			if (c == '\n' || c == -1) {
249 				db_error("Bad escape\n");
250 				/*NOTREACHED*/
251 			}
252 		}
253 		*cp++ = c;
254 		while (1) {
255 			c = db_read_char();
256 			if ((c >= 'A' && c <= 'Z') ||
257 			    (c >= 'a' && c <= 'z') ||
258 			    (c >= '0' && c <= '9') ||
259 			    c == '_' || c == '\\' || c == ':') {
260 				if (c == '\\') {
261 					c = db_read_char();
262 					if (c == '\n' || c == -1) {
263 						db_error("Bad escape\n");
264 						/*NOTREACHED*/
265 					}
266 				}
267 				*cp++ = c;
268 				if (cp == db_tok_string+sizeof(db_tok_string)) {
269 					db_error("String too long\n");
270 					/*NOTREACHED*/
271 				}
272 				continue;
273 			} else {
274 				*cp = '\0';
275 				break;
276 			}
277 		}
278 		db_unread_char(c);
279 		return (tIDENT);
280 	}
281 
282 	switch (c) {
283 	case '+':
284 		return (tPLUS);
285 	case '-':
286 		return (tMINUS);
287 	case '.':
288 		c = db_read_char();
289 		if (c == '.')
290 			return (tDOTDOT);
291 		db_unread_char(c);
292 		return (tDOT);
293 	case '*':
294 		return (tSTAR);
295 	case '/':
296 		return (tSLASH);
297 	case '=':
298 		return (tEQ);
299 	case '%':
300 		return (tPCT);
301 	case '#':
302 		return (tHASH);
303 	case '(':
304 		return (tLPAREN);
305 	case ')':
306 		return (tRPAREN);
307 	case ',':
308 		return (tCOMMA);
309 	case '"':
310 		return (tDITTO);
311 	case '$':
312 		return (tDOLLAR);
313 	case '!':
314 		return (tEXCL);
315 	case '<':
316 		c = db_read_char();
317 		if (c == '<')
318 			return (tSHIFT_L);
319 		db_unread_char(c);
320 		break;
321 	case '>':
322 		c = db_read_char();
323 		if (c == '>')
324 			return (tSHIFT_R);
325 		db_unread_char(c);
326 		break;
327 	case -1:
328 		return (tEOF);
329 	}
330 	db_printf("Bad character\n");
331 	db_flush_lex();
332 	return (tEOF);
333 }
334