]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_lex.c
8a1ec12614eb168f17e7d5ffcbe53c2db57b6d14
[apple/xnu.git] / osfmk / ddb / db_lex.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * @OSF_COPYRIGHT@
25 */
26 /*
27 * HISTORY
28 *
29 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
30 * Import of Mac OS X kernel (~semeria)
31 *
32 * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez
33 * Import of OSF Mach kernel (~mburg)
34 *
35 * Revision 1.1.11.3 1996/01/09 19:15:49 devrcs
36 * Change 'register foo' to 'register int foo'.
37 * [1995/12/01 21:42:12 jfraser]
38 *
39 * Merged '64-bit safe' changes from DEC alpha port.
40 * [1995/11/21 18:03:11 jfraser]
41 *
42 * Revision 1.1.11.2 1995/01/06 19:10:21 devrcs
43 * mk6 CR668 - 1.3b26 merge
44 * * Revision 1.1.4.6 1994/05/06 18:39:20 tmt
45 * Merged osc1.3dec/shared with osc1.3b19
46 * Merge Alpha changes into osc1.312b source code.
47 * String protos.
48 * 64bit cleanup.
49 * Cleanup to quiet gcc warnings.
50 * * End1.3merge
51 * [1994/11/04 08:49:35 dwm]
52 *
53 * Revision 1.1.11.1 1994/09/23 01:19:59 ezf
54 * change marker to not FREE
55 * [1994/09/22 21:10:14 ezf]
56 *
57 * Revision 1.1.4.4 1993/08/11 20:37:55 elliston
58 * Add ANSI Prototypes. CR #9523.
59 * [1993/08/11 03:33:26 elliston]
60 *
61 * Revision 1.1.4.3 1993/07/27 18:27:38 elliston
62 * Add ANSI prototypes. CR #9523.
63 * [1993/07/27 18:12:13 elliston]
64 *
65 * Revision 1.1.4.2 1993/06/02 23:11:27 jeffc
66 * Added to OSF/1 R1.3 from NMK15.0.
67 * [1993/06/02 20:56:32 jeffc]
68 *
69 * Revision 1.1 1992/09/30 02:01:10 robert
70 * Initial revision
71 *
72 * $EndLog$
73 */
74 /* CMU_HIST */
75 /*
76 * Revision 2.5 91/10/09 16:00:20 af
77 * Revision 2.4.3.1 91/10/05 13:06:25 jeffreyh
78 * Added relational operator tokens and string constant etc.
79 * Added input switching functions for macro and conditional command.
80 * Moved skip_to_eol() from db_command.c and added db_last_lp to print
81 * skipped input data as a warning message.
82 * Added last input repetition support to db_read_line.
83 * Changed db_lex() to always set db_tok_string for error message.
84 * [91/08/29 tak]
85 *
86 * Revision 2.4.3.1 91/10/05 13:06:25 jeffreyh
87 * Added relational operator tokens and string constant etc.
88 * Added input switching functions for macro and conditional command.
89 * Moved skip_to_eol() from db_command.c and added db_last_lp to print
90 * skipped input data as a warning message.
91 * Added last input repetition support to db_read_line.
92 * Changed db_lex() to always set db_tok_string for error message.
93 * [91/08/29 tak]
94 *
95 * Revision 2.4 91/05/14 15:34:23 mrt
96 * Correcting copyright
97 *
98 * Revision 2.3 91/02/05 17:06:36 mrt
99 * Changed to new Mach copyright
100 * [91/01/31 16:18:20 mrt]
101 *
102 * Revision 2.2 90/08/27 21:51:10 dbg
103 * Add 'dotdot' token.
104 * [90/08/22 dbg]
105 *
106 * Allow backslash to quote any character into an identifier.
107 * Allow colon in identifier for symbol table qualification.
108 * [90/08/16 dbg]
109 * Reduce lint.
110 * [90/08/07 dbg]
111 * Created.
112 * [90/07/25 dbg]
113 *
114 */
115 /* CMU_ENDHIST */
116 /*
117 * Mach Operating System
118 * Copyright (c) 1991,1990 Carnegie Mellon University
119 * All Rights Reserved.
120 *
121 * Permission to use, copy, modify and distribute this software and its
122 * documentation is hereby granted, provided that both the copyright
123 * notice and this permission notice appear in all copies of the
124 * software, derivative works or modified versions, and any portions
125 * thereof, and that both notices appear in supporting documentation.
126 *
127 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
128 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
129 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
130 *
131 * Carnegie Mellon requests users of this software to return to
132 *
133 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
134 * School of Computer Science
135 * Carnegie Mellon University
136 * Pittsburgh PA 15213-3890
137 *
138 * any improvements or extensions that they make and grant Carnegie Mellon
139 * the rights to redistribute these changes.
140 */
141 /*
142 */
143 /*
144 * Author: David B. Golub, Carnegie Mellon University
145 * Date: 7/90
146 */
147 /*
148 * Lexical analyzer.
149 */
150 #include <string.h> /* For strcpy(), strncmp(), strlen() */
151 #include <ddb/db_lex.h>
152 #include <ddb/db_command.h>
153 #include <ddb/db_input.h>
154 #include <ddb/db_output.h> /* For db_printf() */
155
156 char db_line[DB_LEX_LINE_SIZE];
157 char db_last_line[DB_LEX_LINE_SIZE];
158 char *db_lp, *db_endlp;
159 char *db_last_lp;
160 int db_look_char = 0;
161 db_expr_t db_look_token = 0;
162
163
164 /* Prototypes for functions local to this file. XXX -- should be static!
165 */
166 void db_flush_line(void);
167 void db_unread_char(int c);
168
169
170 int
171 db_read_line(char *repeat_last)
172 {
173 int i;
174
175 i = db_readline(db_line, sizeof(db_line));
176 if (i == 0)
177 return (0); /* EOI */
178 if (repeat_last) {
179 if (strncmp(db_line, repeat_last, strlen(repeat_last)) == 0) {
180 strcpy(db_line, db_last_line);
181 db_printf("%s", db_line);
182 i = strlen(db_line);
183 } else if (db_line[0] != '\n' && db_line[0] != 0)
184 strcpy(db_last_line, db_line);
185 }
186 db_lp = db_line;
187 db_endlp = db_lp + i;
188 db_last_lp = db_lp;
189 db_look_char = 0;
190 db_look_token = 0;
191 return (i);
192 }
193
194 void
195 db_flush_line(void)
196 {
197 db_lp = db_line;
198 db_last_lp = db_lp;
199 db_endlp = db_line;
200 }
201
202 void
203 db_switch_input(
204 char *buffer,
205 int size)
206 {
207 db_lp = buffer;
208 db_last_lp = db_lp;
209 db_endlp = buffer + size;
210 db_look_char = 0;
211 db_look_token = 0;
212 }
213
214 void
215 db_save_lex_context(register struct db_lex_context *lp)
216 {
217 lp->l_ptr = db_lp;
218 lp->l_eptr = db_endlp;
219 lp->l_char = db_look_char;
220 lp->l_token = db_look_token;
221 }
222
223 void
224 db_restore_lex_context(register struct db_lex_context *lp)
225 {
226 db_lp = lp->l_ptr;
227 db_last_lp = db_lp;
228 db_endlp = lp->l_eptr;
229 db_look_char = lp->l_char;
230 db_look_token = lp->l_token;
231 }
232
233 int
234 db_read_char(void)
235 {
236 int c;
237
238 if (db_look_char != 0) {
239 c = db_look_char;
240 db_look_char = 0;
241 }
242 else if (db_lp >= db_endlp)
243 c = -1;
244 else
245 c = *db_lp++;
246 return (c);
247 }
248
249 void
250 db_unread_char(int c)
251 {
252 db_look_char = c;
253 }
254
255 void
256 db_unread_token(int t)
257 {
258 db_look_token = t;
259 }
260
261 int
262 db_read_token(void)
263 {
264 int t;
265
266 if (db_look_token) {
267 t = db_look_token;
268 db_look_token = 0;
269 }
270 else {
271 db_last_lp = db_lp;
272 if (db_look_char)
273 db_last_lp--;
274 t = db_lex();
275 }
276 return (t);
277 }
278
279 db_expr_t db_tok_number;
280 char db_tok_string[TOK_STRING_SIZE];
281
282 db_expr_t db_radix = 16;
283
284 void
285 db_flush_lex(void)
286 {
287 db_flush_line();
288 db_look_char = 0;
289 db_look_token = 0;
290 }
291
292 #define DB_DISP_SKIP 40 /* number of chars to display skip */
293
294 void
295 db_skip_to_eol(void)
296 {
297 register int skip;
298 register int t;
299 register int n;
300 register char *p;
301
302 t = db_read_token();
303 p = db_last_lp;
304 for (skip = 0; t != tEOL && t != tSEMI_COLON && t != tEOF; skip++)
305 t = db_read_token();
306 if (t == tSEMI_COLON)
307 db_unread_token(t);
308 if (skip != 0) {
309 while (p < db_last_lp && (*p == ' ' || *p == '\t'))
310 p++;
311 db_printf("Warning: Skipped input data \"");
312 for (n = 0; n < DB_DISP_SKIP && p < db_last_lp; n++)
313 db_printf("%c", *p++);
314 if (n >= DB_DISP_SKIP)
315 db_printf("....");
316 db_printf("\"\n");
317 }
318 }
319
320 int
321 db_lex(void)
322 {
323 register char *cp;
324 register int c;
325
326 c = db_read_char();
327 while (c <= ' ' || c > '~') {
328 if (c == '\n' || c == -1)
329 return (tEOL);
330 c = db_read_char();
331 }
332
333 cp = db_tok_string;
334 *cp++ = c;
335
336 if (c >= '0' && c <= '9') {
337 /* number */
338 int r, digit;
339
340 if (c > '0')
341 r = db_radix;
342 else {
343 c = db_read_char();
344 if (c == 'O' || c == 'o')
345 r = 8;
346 else if (c == 'T' || c == 't')
347 r = 10;
348 else if (c == 'X' || c == 'x')
349 r = 16;
350 else {
351 cp--;
352 r = db_radix;
353 db_unread_char(c);
354 }
355 c = db_read_char();
356 *cp++ = c;
357 }
358 db_tok_number = 0;
359 for (;;) {
360 if (c >= '0' && c <= ((r == 8) ? '7' : '9'))
361 digit = c - '0';
362 else if (r == 16 && ((c >= 'A' && c <= 'F') ||
363 (c >= 'a' && c <= 'f'))) {
364 if (c >= 'a')
365 digit = c - 'a' + 10;
366 else
367 digit = c - 'A' + 10;
368 }
369 else
370 break;
371 db_tok_number = db_tok_number * r + digit;
372 c = db_read_char();
373 if (cp < &db_tok_string[sizeof(db_tok_string)-1])
374 *cp++ = c;
375 }
376 cp[-1] = 0;
377 if ((c >= '0' && c <= '9') ||
378 (c >= 'A' && c <= 'Z') ||
379 (c >= 'a' && c <= 'z') ||
380 (c == '_'))
381 {
382 db_printf("Bad character '%c' after number %s\n",
383 c, db_tok_string);
384 db_error(0);
385 db_flush_lex();
386 return (tEOF);
387 }
388 db_unread_char(c);
389 return (tNUMBER);
390 }
391 if ((c >= 'A' && c <= 'Z') ||
392 (c >= 'a' && c <= 'z') ||
393 c == '_' || c == '\\' || c == ':')
394 {
395 /* identifier */
396 if (c == '\\') {
397 c = db_read_char();
398 if (c == '\n' || c == -1)
399 db_error("Bad '\\' at the end of line\n");
400 cp[-1] = c;
401 }
402 while (1) {
403 c = db_read_char();
404 if ((c >= 'A' && c <= 'Z') ||
405 (c >= 'a' && c <= 'z') ||
406 (c >= '0' && c <= '9') ||
407 c == '_' || c == '\\' || c == ':' || c == '.')
408 {
409 if (c == '\\') {
410 c = db_read_char();
411 if (c == '\n' || c == -1)
412 db_error("Bad '\\' at the end of line\n");
413 }
414 *cp++ = c;
415 if (cp == db_tok_string+sizeof(db_tok_string)) {
416 db_error("String too long\n");
417 db_flush_lex();
418 return (tEOF);
419 }
420 continue;
421 }
422 else {
423 *cp = '\0';
424 break;
425 }
426 }
427 db_unread_char(c);
428 return (tIDENT);
429 }
430
431 *cp = 0;
432 switch (c) {
433 case '+':
434 return (tPLUS);
435 case '-':
436 return (tMINUS);
437 case '.':
438 c = db_read_char();
439 if (c == '.') {
440 *cp++ = c;
441 *cp = 0;
442 return (tDOTDOT);
443 }
444 db_unread_char(c);
445 return (tDOT);
446 case '*':
447 return (tSTAR);
448 case '/':
449 return (tSLASH);
450 case '=':
451 c = db_read_char();
452 if (c == '=') {
453 *cp++ = c;
454 *cp = 0;
455 return(tLOG_EQ);
456 }
457 db_unread_char(c);
458 return (tEQ);
459 case '%':
460 return (tPCT);
461 case '#':
462 return (tHASH);
463 case '(':
464 return (tLPAREN);
465 case ')':
466 return (tRPAREN);
467 case ',':
468 return (tCOMMA);
469 case '\'':
470 return (tQUOTE);
471 case '"':
472 /* string */
473 cp = db_tok_string;
474 c = db_read_char();
475 while (c != '"' && c > 0 && c != '\n') {
476 if (cp >= &db_tok_string[sizeof(db_tok_string)-1]) {
477 db_error("Too long string\n");
478 db_flush_lex();
479 return (tEOF);
480 }
481 if (c == '\\') {
482 c = db_read_char();
483 switch(c) {
484 case 'n':
485 c = '\n'; break;
486 case 't':
487 c = '\t'; break;
488 case '\\':
489 case '"':
490 break;
491 default:
492 db_printf("Bad escape sequence '\\%c'\n", c);
493 db_error(0);
494 db_flush_lex();
495 return (tEOF);
496 }
497 }
498 *cp++ = c;
499 c = db_read_char();
500 }
501 *cp = 0;
502 if (c != '"') {
503 db_error("Non terminated string constant\n");
504 db_flush_lex();
505 return (tEOF);
506 }
507 return (tSTRING);
508 case '$':
509 return (tDOLLAR);
510 case '!':
511 c = db_read_char();
512 if (c == '=') {
513 *cp++ = c;
514 *cp = 0;
515 return(tLOG_NOT_EQ);
516 }
517 db_unread_char(c);
518 return (tEXCL);
519 case '&':
520 c = db_read_char();
521 if (c == '&') {
522 *cp++ = c;
523 *cp = 0;
524 return(tLOG_AND);
525 }
526 db_unread_char(c);
527 return(tBIT_AND);
528 case '|':
529 c = db_read_char();
530 if (c == '|') {
531 *cp++ = c;
532 *cp = 0;
533 return(tLOG_OR);
534 }
535 db_unread_char(c);
536 return(tBIT_OR);
537 case '<':
538 c = db_read_char();
539 *cp++ = c;
540 *cp = 0;
541 if (c == '<')
542 return (tSHIFT_L);
543 if (c == '=')
544 return (tLESS_EQ);
545 cp[-1] = 0;
546 db_unread_char(c);
547 return(tLESS);
548 break;
549 case '>':
550 c = db_read_char();
551 *cp++ = c;
552 *cp = 0;
553 if (c == '>')
554 return (tSHIFT_R);
555 if (c == '=')
556 return (tGREATER_EQ);
557 cp[-1] = 0;
558 db_unread_char(c);
559 return (tGREATER);
560 break;
561 case ';':
562 return (tSEMI_COLON);
563 case '?':
564 return (tQUESTION);
565 case -1:
566 strcpy(db_tok_string, "<EOL>");
567 return (tEOF);
568 }
569 db_printf("Bad character '%c'\n", c);
570 db_flush_lex();
571 return (tEOF);
572 }