Index: head/sys/ddb/db_lex.c =================================================================== --- head/sys/ddb/db_lex.c (revision 352073) +++ head/sys/ddb/db_lex.c (revision 352074) @@ -1,345 +1,371 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ /* * Lexical analyzer. */ #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include static char db_line[DB_MAXLINE]; static char * db_lp, *db_endlp; -static int db_lex(void); +static int db_lex(int); static void db_flush_line(void); static int db_read_char(void); static void db_unread_char(int); int db_read_line(void) { int i; i = db_readline(db_line, sizeof(db_line)); if (i == 0) return (0); /* EOI */ db_lp = db_line; db_endlp = db_lp + i; return (i); } /* * Simulate a line of input into DDB. */ void db_inject_line(const char *command) { strlcpy(db_line, command, sizeof(db_line)); db_lp = db_line; db_endlp = db_lp + strlen(command); } /* * In rare cases, we may want to pull the remainder of the line input * verbatim, rather than lexing it. For example, when assigning literal * values associated with scripts. In that case, return a static pointer to * the current location in the input buffer. The caller must be aware that * the contents are not stable if other lex/input calls are made. */ char * db_get_line(void) { return (db_lp); } static void db_flush_line() { db_lp = db_line; db_endlp = db_line; } static int db_look_char = 0; static int db_read_char(void) { int c; if (db_look_char != 0) { c = db_look_char; db_look_char = 0; } else if (db_lp >= db_endlp) c = -1; else c = *db_lp++; return (c); } static void db_unread_char(c) int c; { db_look_char = c; } static int db_look_token = 0; void -db_unread_token(t) - int t; +db_unread_token(int t) { db_look_token = t; } int -db_read_token() +db_read_token_flags(int flags) { int t; + MPASS((flags & ~(DRT_VALID_FLAGS_MASK)) == 0); + if (db_look_token) { t = db_look_token; db_look_token = 0; } else - t = db_lex(); + t = db_lex(flags); return (t); } db_expr_t db_tok_number; char db_tok_string[TOK_STRING_SIZE]; db_expr_t db_radix = 16; void db_flush_lex(void) { db_flush_line(); db_look_char = 0; db_look_token = 0; } static int -db_lex(void) +db_lex(int flags) { - int c; + int c, n, radix_mode; + bool lex_wspace; + switch (flags & DRT_RADIX_MASK) { + case DRT_DEFAULT_RADIX: + radix_mode = -1; + break; + case DRT_OCTAL: + radix_mode = 8; + break; + case DRT_DECIMAL: + radix_mode = 10; + break; + case DRT_HEXADECIMAL: + radix_mode = 16; + break; + } + + lex_wspace = ((flags & DRT_WSPACE) != 0); + c = db_read_char(); - while (c <= ' ' || c > '~') { + for (n = 0; c <= ' ' || c > '~'; n++) { if (c == '\n' || c == -1) return (tEOL); c = db_read_char(); } + if (lex_wspace && n != 0) { + db_unread_char(c); + return (tWSPACE); + } if (c >= '0' && c <= '9') { /* number */ int r, digit = 0; - if (c > '0') + if (radix_mode != -1) + r = radix_mode; + else if (c > '0') r = db_radix; else { c = db_read_char(); if (c == 'O' || c == 'o') r = 8; else if (c == 'T' || c == 't') r = 10; else if (c == 'X' || c == 'x') r = 16; else { r = db_radix; db_unread_char(c); } c = db_read_char(); } db_tok_number = 0; for (;;) { if (c >= '0' && c <= ((r == 8) ? '7' : '9')) digit = c - '0'; else if (r == 16 && ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) { if (c >= 'a') digit = c - 'a' + 10; else if (c >= 'A') digit = c - 'A' + 10; } else break; db_tok_number = db_tok_number * r + digit; c = db_read_char(); } if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c == '_')) { db_error("Bad character in number\n"); db_flush_lex(); return (tEOF); } db_unread_char(c); return (tNUMBER); } if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || c == '\\') { /* string */ char *cp; cp = db_tok_string; if (c == '\\') { c = db_read_char(); if (c == '\n' || c == -1) db_error("Bad escape\n"); } *cp++ = c; while (1) { c = db_read_char(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c == '\\' || c == ':' || c == '.') { if (c == '\\') { c = db_read_char(); if (c == '\n' || c == -1) db_error("Bad escape\n"); } *cp++ = c; if (cp == db_tok_string+sizeof(db_tok_string)) { db_error("String too long\n"); db_flush_lex(); return (tEOF); } continue; } else { *cp = '\0'; break; } } db_unread_char(c); return (tIDENT); } switch (c) { case '+': return (tPLUS); case '-': return (tMINUS); case '.': c = db_read_char(); if (c == '.') return (tDOTDOT); db_unread_char(c); return (tDOT); case '*': return (tSTAR); case '/': return (tSLASH); case '=': c = db_read_char(); if (c == '=') return (tLOG_EQ); db_unread_char(c); return (tEQ); case '%': return (tPCT); case '#': return (tHASH); case '(': return (tLPAREN); case ')': return (tRPAREN); case ',': return (tCOMMA); case '"': return (tDITTO); case '$': return (tDOLLAR); case '!': c = db_read_char(); if (c == '='){ return (tLOG_NOT_EQ); } db_unread_char(c); return (tEXCL); case ';': return (tSEMI); case '&': c = db_read_char(); if (c == '&') return (tLOG_AND); db_unread_char(c); return (tBIT_AND); case '|': c = db_read_char(); if (c == '|') return (tLOG_OR); db_unread_char(c); return (tBIT_OR); case '<': c = db_read_char(); if (c == '<') return (tSHIFT_L); if (c == '=') return (tLESS_EQ); db_unread_char(c); return (tLESS); case '>': c = db_read_char(); if (c == '>') return (tSHIFT_R); if (c == '=') return (tGREATER_EQ); db_unread_char(c); return (tGREATER); case '?': return (tQUESTION); case '~': return (tBIT_NOT); case -1: return (tEOF); } db_printf("Bad character\n"); db_flush_lex(); return (tEOF); } Index: head/sys/ddb/db_lex.h =================================================================== --- head/sys/ddb/db_lex.h (revision 352073) +++ head/sys/ddb/db_lex.h (revision 352074) @@ -1,88 +1,127 @@ /*- * SPDX-License-Identifier: MIT-CMU * * Mach Operating System * Copyright (c) 1991,1990 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. * * $FreeBSD$ */ #ifndef _DDB_DB_LEX_H_ #define _DDB_DB_LEX_H_ /* * Author: David B. Golub, Carnegie Mellon University * Date: 7/90 */ /* * Lexical analyzer. */ + +/* + * Options and flags can configure db_read_token() => db_lex() behavior. + * + * When a radix other than DRT_DEFAULT_RADIX is used, it overrides + * auto-detection, as well as the user-specified db_radix, in db_lex() of + * 'tNUMBER' tokens. + */ +enum { + /* Infer or use db_radix using the old logic. */ + DRT_DEFAULT_RADIX = 0, + /* The following set an explicit base for tNUMBER lex. */ + DRT_OCTAL, + DRT_DECIMAL, + DRT_HEXADECIMAL, +}; +#define DRT_RADIX_MASK 0x3 +/* + * Flag bit powers of two for db_read_token_flags. + * The low 2 bits are reserved for radix selection. + */ +enum { + _DRT_WSPACE = 2, +}; +#ifndef BIT +#define BIT(n) (1ull << (n)) +#endif +enum { + DRT_WSPACE = BIT(_DRT_WSPACE), +}; +#define DRT_VALID_FLAGS_MASK ((int)DRT_RADIX_MASK | DRT_WSPACE) + void db_flush_lex(void); char *db_get_line(void); void db_inject_line(const char *command); int db_read_line(void); -int db_read_token(void); +int db_read_token_flags(int); void db_unread_token(int t); +static inline int +db_read_token(void) +{ + return (db_read_token_flags(0)); +} + extern db_expr_t db_tok_number; #define TOK_STRING_SIZE 120 extern char db_tok_string[TOK_STRING_SIZE]; #define tEOF (-1) #define tEOL 1 #define tNUMBER 2 #define tIDENT 3 #define tPLUS 4 #define tMINUS 5 #define tDOT 6 #define tSTAR 7 #define tSLASH 8 #define tEQ 9 #define tLPAREN 10 #define tRPAREN 11 #define tPCT 12 #define tHASH 13 #define tCOMMA 14 #define tDITTO 15 #define tDOLLAR 16 #define tEXCL 17 #define tSHIFT_L 18 #define tSHIFT_R 19 #define tDOTDOT 20 #define tSEMI 21 #define tLOG_EQ 22 #define tLOG_NOT_EQ 23 #define tLESS 24 #define tLESS_EQ 25 #define tGREATER 26 #define tGREATER_EQ 27 #define tBIT_AND 28 #define tBIT_OR 29 #define tLOG_AND 30 #define tLOG_OR 31 #define tSTRING 32 #define tQUESTION 33 #define tBIT_NOT 34 +#define tWSPACE 35 #endif /* !_DDB_DB_LEX_H_ */