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