xref: /openbsd-src/sys/ddb/db_lex.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: db_lex.c,v 1.10 2014/07/08 13:02:57 deraadt Exp $	*/
2 /*	$NetBSD: db_lex.c,v 1.8 1996/02/05 01:57:05 christos Exp $	*/
3 
4 /*
5  * Mach Operating System
6  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
7  * All Rights Reserved.
8  *
9  * Permission to use, copy, modify and distribute this software and its
10  * documentation is hereby granted, provided that both the copyright
11  * notice and this permission notice appear in all copies of the
12  * software, derivative works or modified versions, and any portions
13  * thereof, and that both notices appear in supporting documentation.
14  *
15  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
17  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18  *
19  * Carnegie Mellon requests users of this software to return to
20  *
21  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
22  *  School of Computer Science
23  *  Carnegie Mellon University
24  *  Pittsburgh PA 15213-3890
25  *
26  * any improvements or extensions that they make and grant Carnegie Mellon
27  * the rights to redistribute these changes.
28  *
29  *	Author: David B. Golub, Carnegie Mellon University
30  *	Date:	7/90
31  */
32 
33 /*
34  * Lexical analyzer.
35  */
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/proc.h>
39 
40 #include <machine/db_machdep.h>
41 
42 #include <ddb/db_lex.h>
43 #include <ddb/db_output.h>
44 #include <ddb/db_command.h>
45 #include <ddb/db_sym.h>
46 #include <ddb/db_extern.h>
47 #include <ddb/db_var.h>
48 
49 char	db_line[120];
50 char *	db_lp, *db_endlp;
51 
52 db_expr_t db_tok_number;
53 char	db_tok_string[TOK_STRING_SIZE];
54 
55 int
56 db_read_line(void)
57 {
58 	int	i;
59 
60 	i = db_readline(db_line, sizeof(db_line));
61 	if (i == 0)
62 	    return (0);	/* EOI */
63 	db_lp = db_line;
64 	db_endlp = db_lp + i;
65 	return (i);
66 }
67 
68 void
69 db_flush_line(void)
70 {
71 	db_lp = db_line;
72 	db_endlp = db_line;
73 }
74 
75 int	db_look_char = 0;
76 
77 int
78 db_read_char(void)
79 {
80 	int	c;
81 
82 	if (db_look_char != 0) {
83 	    c = db_look_char;
84 	    db_look_char = 0;
85 	}
86 	else if (db_lp >= db_endlp)
87 	    c = -1;
88 	else
89 	    c = *db_lp++;
90 	return (c);
91 }
92 
93 void
94 db_unread_char(int c)
95 {
96 	db_look_char = c;
97 }
98 
99 int	db_look_token = 0;
100 
101 void
102 db_unread_token(int t)
103 {
104 	db_look_token = t;
105 }
106 
107 int
108 db_read_token(void)
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 void
122 db_flush_lex(void)
123 {
124 	db_flush_line();
125 	db_look_char = 0;
126 	db_look_token = 0;
127 }
128 
129 int
130 db_lex(void)
131 {
132 	int	c;
133 
134 	c = db_read_char();
135 	while (c <= ' ' || c > '~') {
136 	    if (c == '\n' || c == -1)
137 		return (tEOL);
138 	    c = db_read_char();
139 	}
140 
141 	if (c >= '0' && c <= '9') {
142 	    /* number */
143 	    int	r, digit = 0;
144 
145 	    if (c > '0')
146 		r = db_radix;
147 	    else {
148 		c = db_read_char();
149 		if (c == 'O' || c == 'o')
150 		    r = 8;
151 		else if (c == 'T' || c == 't')
152 		    r = 10;
153 		else if (c == 'X' || c == 'x')
154 		    r = 16;
155 		else {
156 		    r = db_radix;
157 		    db_unread_char(c);
158 		}
159 		c = db_read_char();
160 	    }
161 	    db_tok_number = 0;
162 	    for (;;) {
163 		if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
164 		    digit = c - '0';
165 		else if (r == 16 && ((c >= 'A' && c <= 'F') ||
166 				     (c >= 'a' && c <= 'f'))) {
167 		    if (c >= 'a')
168 			digit = c - 'a' + 10;
169 		    else if (c >= 'A')
170 			digit = c - 'A' + 10;
171 		}
172 		else
173 		    break;
174 		db_tok_number = db_tok_number * r + digit;
175 		c = db_read_char();
176 	    }
177 	    if ((c >= '0' && c <= '9') ||
178 		(c >= 'A' && c <= 'Z') ||
179 		(c >= 'a' && c <= 'z') ||
180 		(c == '_'))
181 	    {
182 		db_error("Bad character in number\n");
183 		/*NOTREACHED*/
184 	    }
185 	    db_unread_char(c);
186 	    return (tNUMBER);
187 	}
188 	if ((c >= 'A' && c <= 'Z') ||
189 	    (c >= 'a' && c <= 'z') ||
190 	    c == '_' || c == '\\')
191 	{
192 	    /* string */
193 	    char *cp;
194 
195 	    cp = db_tok_string;
196 	    if (c == '\\') {
197 		c = db_read_char();
198 		if (c == '\n' || c == -1) {
199 		    db_error("Bad escape\n");
200 		    /*NOTREACHED*/
201 		}
202 	    }
203 	    *cp++ = c;
204 	    while (1) {
205 		c = db_read_char();
206 		if ((c >= 'A' && c <= 'Z') ||
207 		    (c >= 'a' && c <= 'z') ||
208 		    (c >= '0' && c <= '9') ||
209 		    c == '_' || c == '\\' || c == ':')
210 		{
211 		    if (c == '\\') {
212 			c = db_read_char();
213 			if (c == '\n' || c == -1) {
214 			    db_error("Bad escape\n");
215 			    /*NOTREACHED*/
216 			}
217 		    }
218 		    *cp++ = c;
219 		    if (cp == db_tok_string+sizeof(db_tok_string)) {
220 			db_error("String too long\n");
221 			/*NOTREACHED*/
222 		    }
223 		    continue;
224 		}
225 		else {
226 		    *cp = '\0';
227 		    break;
228 		}
229 	    }
230 	    db_unread_char(c);
231 	    return (tIDENT);
232 	}
233 
234 	switch (c) {
235 	    case '+':
236 		return (tPLUS);
237 	    case '-':
238 		return (tMINUS);
239 	    case '.':
240 		c = db_read_char();
241 		if (c == '.')
242 		    return (tDOTDOT);
243 		db_unread_char(c);
244 		return (tDOT);
245 	    case '*':
246 		return (tSTAR);
247 	    case '/':
248 		return (tSLASH);
249 	    case '=':
250 		return (tEQ);
251 	    case '%':
252 		return (tPCT);
253 	    case '#':
254 		return (tHASH);
255 	    case '(':
256 		return (tLPAREN);
257 	    case ')':
258 		return (tRPAREN);
259 	    case ',':
260 		return (tCOMMA);
261 	    case '"':
262 		return (tDITTO);
263 	    case '$':
264 		return (tDOLLAR);
265 	    case '!':
266 		return (tEXCL);
267 	    case '<':
268 		c = db_read_char();
269 		if (c == '<')
270 		    return (tSHIFT_L);
271 		db_unread_char(c);
272 		break;
273 	    case '>':
274 		c = db_read_char();
275 		if (c == '>')
276 		    return (tSHIFT_R);
277 		db_unread_char(c);
278 		break;
279 	    case -1:
280 		return (tEOF);
281 	}
282 	db_printf("Bad character\n");
283 	db_flush_lex();
284 	return (tEOF);
285 }
286