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