1 /* $OpenBSD: db_lex.c,v 1.14 2016/04/19 12:23:25 mpi Exp $ */ 2 /* $NetBSD: db_lex.c,v 1.8 1996/02/05 01:57:05 christos Exp $ */ 3 4 /* 5 * Mach Operating System 6 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 7 * All Rights Reserved. 8 * 9 * Permission to use, copy, modify and distribute this software and its 10 * documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 17 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie Mellon 27 * the rights to redistribute these changes. 28 * 29 * Author: David B. Golub, Carnegie Mellon University 30 * Date: 7/90 31 */ 32 33 /* 34 * Lexical analyzer. 35 */ 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 39 #include <machine/db_machdep.h> 40 41 #include <ddb/db_lex.h> 42 #include <ddb/db_output.h> 43 #include <ddb/db_command.h> 44 #include <ddb/db_extern.h> 45 #include <ddb/db_var.h> 46 47 char db_line[120]; 48 char * db_lp, *db_endlp; 49 50 db_expr_t db_tok_number; 51 char db_tok_string[TOK_STRING_SIZE]; 52 53 void db_flush_line(void); 54 int db_read_char(void); 55 void db_unread_char(int); 56 57 int 58 db_read_line(void) 59 { 60 int i; 61 62 i = db_readline(db_line, sizeof(db_line)); 63 if (i == 0) 64 return (0); /* EOI */ 65 db_lp = db_line; 66 db_endlp = db_lp + i; 67 return (i); 68 } 69 70 void 71 db_flush_line(void) 72 { 73 db_lp = db_line; 74 db_endlp = db_line; 75 } 76 77 int db_look_char = 0; 78 79 int 80 db_read_char(void) 81 { 82 int c; 83 84 if (db_look_char != 0) { 85 c = db_look_char; 86 db_look_char = 0; 87 } 88 else if (db_lp >= db_endlp) 89 c = -1; 90 else 91 c = *db_lp++; 92 return (c); 93 } 94 95 void 96 db_unread_char(int c) 97 { 98 db_look_char = c; 99 } 100 101 int db_look_token = 0; 102 103 void 104 db_unread_token(int t) 105 { 106 db_look_token = t; 107 } 108 109 int 110 db_read_token(void) 111 { 112 int t; 113 114 if (db_look_token) { 115 t = db_look_token; 116 db_look_token = 0; 117 } 118 else 119 t = db_lex(); 120 return (t); 121 } 122 123 void 124 db_flush_lex(void) 125 { 126 db_flush_line(); 127 db_look_char = 0; 128 db_look_token = 0; 129 } 130 131 int 132 db_lex(void) 133 { 134 int c; 135 136 c = db_read_char(); 137 while (c <= ' ' || c > '~') { 138 if (c == '\n' || c == -1) 139 return (tEOL); 140 c = db_read_char(); 141 } 142 143 if (c >= '0' && c <= '9') { 144 /* number */ 145 int r, digit = 0; 146 147 if (c > '0') 148 r = db_radix; 149 else { 150 c = db_read_char(); 151 if (c == 'O' || c == 'o') 152 r = 8; 153 else if (c == 'T' || c == 't') 154 r = 10; 155 else if (c == 'X' || c == 'x') 156 r = 16; 157 else { 158 r = db_radix; 159 db_unread_char(c); 160 } 161 c = db_read_char(); 162 } 163 db_tok_number = 0; 164 for (;;) { 165 if (c >= '0' && c <= ((r == 8) ? '7' : '9')) 166 digit = c - '0'; 167 else if (r == 16 && ((c >= 'A' && c <= 'F') || 168 (c >= 'a' && c <= 'f'))) { 169 if (c >= 'a') 170 digit = c - 'a' + 10; 171 else if (c >= 'A') 172 digit = c - 'A' + 10; 173 } 174 else 175 break; 176 db_tok_number = db_tok_number * r + digit; 177 c = db_read_char(); 178 } 179 if ((c >= '0' && c <= '9') || 180 (c >= 'A' && c <= 'Z') || 181 (c >= 'a' && c <= 'z') || 182 (c == '_')) 183 { 184 db_error("Bad character in number\n"); 185 /*NOTREACHED*/ 186 } 187 db_unread_char(c); 188 return (tNUMBER); 189 } 190 if ((c >= 'A' && c <= 'Z') || 191 (c >= 'a' && c <= 'z') || 192 c == '_' || c == '\\') 193 { 194 /* string */ 195 char *cp; 196 197 cp = db_tok_string; 198 if (c == '\\') { 199 c = db_read_char(); 200 if (c == '\n' || c == -1) { 201 db_error("Bad escape\n"); 202 /*NOTREACHED*/ 203 } 204 } 205 *cp++ = c; 206 while (1) { 207 c = db_read_char(); 208 if ((c >= 'A' && c <= 'Z') || 209 (c >= 'a' && c <= 'z') || 210 (c >= '0' && c <= '9') || 211 c == '_' || c == '\\' || c == ':') 212 { 213 if (c == '\\') { 214 c = db_read_char(); 215 if (c == '\n' || c == -1) { 216 db_error("Bad escape\n"); 217 /*NOTREACHED*/ 218 } 219 } 220 *cp++ = c; 221 if (cp == db_tok_string+sizeof(db_tok_string)) { 222 db_error("String too long\n"); 223 /*NOTREACHED*/ 224 } 225 continue; 226 } 227 else { 228 *cp = '\0'; 229 break; 230 } 231 } 232 db_unread_char(c); 233 return (tIDENT); 234 } 235 236 switch (c) { 237 case '+': 238 return (tPLUS); 239 case '-': 240 return (tMINUS); 241 case '.': 242 c = db_read_char(); 243 if (c == '.') 244 return (tDOTDOT); 245 db_unread_char(c); 246 return (tDOT); 247 case '*': 248 return (tSTAR); 249 case '/': 250 return (tSLASH); 251 case '=': 252 return (tEQ); 253 case '%': 254 return (tPCT); 255 case '#': 256 return (tHASH); 257 case '(': 258 return (tLPAREN); 259 case ')': 260 return (tRPAREN); 261 case ',': 262 return (tCOMMA); 263 case '"': 264 return (tDITTO); 265 case '$': 266 return (tDOLLAR); 267 case '!': 268 return (tEXCL); 269 case '<': 270 c = db_read_char(); 271 if (c == '<') 272 return (tSHIFT_L); 273 db_unread_char(c); 274 break; 275 case '>': 276 c = db_read_char(); 277 if (c == '>') 278 return (tSHIFT_R); 279 db_unread_char(c); 280 break; 281 case -1: 282 return (tEOF); 283 } 284 db_printf("Bad character\n"); 285 db_flush_lex(); 286 return (tEOF); 287 } 288