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