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