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