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