blob: e777039c7bc8134d8ba7a28fa62b509d62f0d960 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001%pointer /* Make yytext a pointer, not an array */
2
3%{
4/*
5 * CDDL HEADER START
6 *
7 * The contents of this file are subject to the terms of the
Scott Rotondod67944f2009-05-21 22:03:24 -07008 * Common Development and Distribution License (the "License").
9 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070010 *
11 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
12 * or http://www.opensolaris.org/os/licensing.
13 * See the License for the specific language governing permissions
14 * and limitations under the License.
15 *
16 * When distributing Covered Code, include this CDDL HEADER in each
17 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
18 * If applicable, add the following below this CDDL HEADER, with the
19 * fields enclosed by brackets "[]" replaced with your own identifying
20 * information: Portions Copyright [yyyy] [name of copyright owner]
21 *
22 * CDDL HEADER END
23 *
Scott Rotondod67944f2009-05-21 22:03:24 -070024 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070025 * Use is subject to license terms.
26 */
27
Alexander Eremina11593b2011-05-17 12:36:01 -040028/*
29 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
Serapheim Dimitropoulos3d580ed2017-01-11 08:47:43 -080030 * Copyright (c) 2017 by Delphix. All rights reserved.
Alexander Eremina11593b2011-05-17 12:36:01 -040031 */
32
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070033#include <sys/types.h>
34#include <sys/isa_defs.h>
35
36#include <strings.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <stdio.h>
40#include <errno.h>
41
42#include <mdb/mdb_types.h>
43#include <mdb/mdb_debug.h>
44#include <mdb/mdb_nv.h>
45#include <mdb/mdb_lex.h>
46#include <mdb/mdb_frame.h>
47#include <mdb/mdb_string.h>
48#include <mdb/mdb_stdlib.h>
49#include <mdb/mdb_err.h>
50#include <mdb/mdb.h>
51
52#include "mdb_grammar.h"
53
54/*
55 * lex hardcodes yyin and yyout to stdin and stdout, respectively, before we get
56 * control. We've redirected printf and fprintf (see mdb_lex.h) to yyprintf and
57 * yyfprintf, which ignore the FILE * provided by yyout. __iob-based stdin and
58 * stdout are useless in kmdb, since we don't have stdio. We define __iob here
59 * to shut the linker up.
60 */
61#ifdef _KMDB
Scott Rotondod67944f2009-05-21 22:03:24 -070062FILE __iob[_NFILE];
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070063#endif
64
65/*
66 * We need to undefine lex's input, unput, and output macros so that references
67 * to these call the functions we provide at the end of this source file,
68 * instead of the default versions based on libc's stdio.
69 */
70#ifdef input
71#undef input
72#endif
73
74#ifdef unput
75#undef unput
76#endif
77
78#ifdef output
79#undef output
80#endif
81
82static int input(void);
83static void unput(int);
84static void output(int);
85
86static void string_unquote(char *);
87
88extern int yydebug;
89
90/*
91 * This will prevent lex from trying to malloc() and resize our yytext variable,
92 * instead it will just print out an error message and exit(), which seems
93 * a lesser of two evils.
94 */
95#define YYISARRAY
96
97%}
98
99%o 9000
100%a 5000
101
102%s S_SHELLCMD
103%s S_INITIAL
104%s S_FMTLIST
105%s S_ARGLIST
106%s S_EXPR
107
108RGX_CMD_CHAR [?%@A-Z\^_`a-z]
109RGX_SYMBOL [a-zA-Z_.][0-9a-zA-Z_.`]*
110RGX_SIMPLE_CHAR [^ \t\n;!|"'\$]
111RGX_CHR_SEQ ([^'\n]|\\[^'\n]|\\')*
112RGX_STR_SEQ ([^"\\\n]|\\[^"\n]|\\\")*
113RGX_COMMENT "//".*\n
114
115%%
116
117<S_INITIAL>{RGX_COMMENT} |
118<S_FMTLIST>{RGX_COMMENT} |
119<S_ARGLIST>{RGX_COMMENT} {
120 /*
121 * Comments are legal in these three states -- if we see one
122 * eat the line and return the newline character.
123 */
124 BEGIN(S_INITIAL);
125 return ('\n');
126 }
127
128<S_INITIAL>"==" |
129<S_EXPR>"==" return (MDB_TOK_EQUAL); /* Equality operator */
130
131<S_INITIAL>"!=" |
132<S_EXPR>"!=" return (MDB_TOK_NOTEQUAL); /* Inequality operator */
133
134<S_INITIAL>"!" |
135<S_FMTLIST>"!" |
136<S_ARGLIST>"!" {
137 /*
138 * Shell escapes are legal in all of these states -- switch to
139 * the shell command state and return the ! character.
140 */
141 BEGIN(S_SHELLCMD);
142 return (yytext[0]);
143 }
144
145<S_FMTLIST>"|" |
146<S_ARGLIST>"|" {
147 /*
148 * Pipelines can appear in any of these states -- switch to
149 * the initial state and return the | character.
150 */
151 BEGIN(S_INITIAL);
152 return (yytext[0]);
153 }
154
155<S_SHELLCMD>[^;\n]+ {
156 /*
157 * Once in the shell-command state, we return all remaining
158 * characters up to a newline or ';' delimiter as a single
159 * string which will be passed to $SHELL -c.
160 */
161 yylval.l_string = strdup(yytext);
162 BEGIN(S_INITIAL);
163 return (MDB_TOK_STRING);
164 }
165
166<S_INITIAL>"::"{RGX_SYMBOL} {
167 /*
168 * Verb ::command-name -- lookup the correspond dcmd and
169 * switch to the argument list state.
170 */
171 if ((yylval.l_dcmd = mdb_dcmd_lookup(yytext + 2)) == NULL)
172 yyperror("invalid command '%s'", yytext);
173
174 BEGIN(S_ARGLIST);
175 return (MDB_TOK_DCMD);
176 }
177
178<S_INITIAL>"$<<"|"$<"|"$>" |
179<S_INITIAL>[\$:]{RGX_CMD_CHAR} {
180 /*
181 * Old-style :c or $c command -- lookup the corresponding dcmd
182 * and switch to the argument list state.
183 */
184 if ((yylval.l_dcmd = mdb_dcmd_lookup(yytext)) == NULL)
185 yyperror("invalid command '%s'", yytext);
186
187 BEGIN(S_ARGLIST);
188 return (MDB_TOK_DCMD);
189 }
190
191<S_INITIAL>">/"[a-zA-Z0-9]"/" {
192 /*
193 * Variable assignment with size cast -- append the cast letter
194 * to the argument list, and switch to the argument list state.
195 */
196 mdb_arg_t arg;
197
198 arg.a_un.a_char = yytext[2];
199 arg.a_type = MDB_TYPE_CHAR;
200
201 mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
202 yylval.l_dcmd = mdb_dcmd_lookup(">");
203
204 BEGIN(S_ARGLIST);
205 return (MDB_TOK_DCMD);
206 }
207
208<S_INITIAL>">" {
209 /*
210 * Variable assignment -- switch to the argument list state.
211 */
212 yylval.l_dcmd = mdb_dcmd_lookup(yytext);
213 BEGIN(S_ARGLIST);
214 return (MDB_TOK_DCMD);
215 }
216
Serapheim Dimitropoulos3d580ed2017-01-11 08:47:43 -0800217<S_INITIAL>[/\\?][ \t]*[vwzWZlLM] {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700218 /*
219 * Format verb followed by write or match signifier -- switch
220 * to the value list state and return the verb character. We
221 * also append the actual format character to the arg list.
222 */
223 mdb_arg_t arg;
224
225 arg.a_un.a_char = yytext[yyleng - 1];
226 arg.a_type = MDB_TYPE_CHAR;
227
228 mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
229
230 BEGIN(S_ARGLIST);
231 return yytext[0];
232 }
233
234<S_INITIAL>[/\\@?=] {
235 /*
236 * Format verb -- switch to the format list state and return
237 * the actual verb character verbatim.
238 */
239 BEGIN(S_FMTLIST);
240 return (yytext[0]);
241 }
242
243<S_INITIAL>'{RGX_CHR_SEQ}$ |
244<S_EXPR>'{RGX_CHR_SEQ}$ yyerror("syntax error: ' unmatched");
245
246<S_INITIAL>'{RGX_CHR_SEQ}' |
247<S_EXPR>'{RGX_CHR_SEQ}' {
248 char *s, *p, *q;
249 size_t nbytes;
250
251 /*
252 * If the character sequence is zero-length, return 0.
253 */
254 if (yyleng == 2) {
255 yylval.l_immediate = 0;
256 return (MDB_TOK_IMMEDIATE);
257 }
258
259 s = yytext + 1; /* Skip past initial quote */
260 yytext[yyleng - 1] = '\0'; /* Overwrite final quote */
261 nbytes = stresc2chr(s); /* Convert escapes */
262 yylval.l_immediate = 0; /* Initialize token value */
263
264 if (nbytes > sizeof (uintmax_t)) {
265 yyerror("character constant may not exceed %lu bytes\n",
266 (ulong_t)sizeof (uintmax_t));
267 }
268
269#ifdef _LITTLE_ENDIAN
270 p = ((char*)&yylval.l_immediate) + nbytes - 1;
271
272 for (q = s; nbytes != 0; nbytes--)
273 *p-- = *q++;
274#else
275 bcopy(s, ((char *)&yylval.l_immediate) +
276 sizeof (uintmax_t) - nbytes, nbytes);
277#endif
278 return (MDB_TOK_IMMEDIATE);
279 }
280
281\"{RGX_STR_SEQ}$ yyerror("syntax error: \" unmatched");
282
283\"{RGX_STR_SEQ}\" {
284 /*
285 * Quoted string -- convert C escape sequences and return the
286 * string as a token.
287 */
288 yylval.l_string = strndup(yytext + 1, yyleng - 2);
289 (void) stresc2chr(yylval.l_string);
290 return (MDB_TOK_STRING);
291 }
292
293<S_ARGLIST>"$[" |
294<S_FMTLIST>"$[" {
295 /*
296 * Start of expression -- begin expression state and save the
297 * current state so we can return at the end of the expression.
298 */
299 mdb.m_frame->f_oldstate = YYSTATE;
300 BEGIN(S_EXPR);
301 return (MDB_TOK_LEXPR);
302 }
303
304<S_ARGLIST>{RGX_SIMPLE_CHAR}*("'"{RGX_CHR_SEQ}"'"|\"{RGX_STR_SEQ}\"|{RGX_SIMPLE_CHAR}+)* {
305 /*
306 * String token -- create a copy of the string and return it.
307 * We need to handle embedded single and double-quote pairs,
308 * which overcomplicates this slightly.
309 */
310 yylval.l_string = strdup(yytext);
311 string_unquote(yylval.l_string);
312 return (MDB_TOK_STRING);
313 }
314
315<S_FMTLIST>[0-9]+ {
316 /*
317 * Immediate value -- in the format list, all immediates
318 * are assumed to be in decimal.
319 */
Yuri Pankov45851302017-06-12 20:16:28 -0700320 yylval.l_immediate = mdb_strtonum(yytext, 10);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700321 return (MDB_TOK_IMMEDIATE);
322 }
323
324<S_FMTLIST>{RGX_SIMPLE_CHAR} {
325 /*
326 * Non-meta character -- in the format list, we return each
327 * character as a separate token to be added as an argument.
328 */
329 yylval.l_char = yytext[0];
330 return (MDB_TOK_CHAR);
331 }
332
333<S_EXPR>";"|"!"|\n {
334 /*
335 * In the expression state only, we cannot see a command
336 * delimiter or shell escape before we end the expression.
337 */
338 yyerror("syntax error: $[ unmatched");
339 }
340
341<S_EXPR>"]" {
342 /*
343 * End of expression state. Restore the state we were in
344 * before the "$[" which started this expression.
345 */
346 BEGIN(mdb.m_frame->f_oldstate);
347 return (MDB_TOK_REXPR);
348 }
349
350<S_INITIAL>"<"{RGX_SYMBOL} |
351<S_INITIAL>"<"[0-9] |
352<S_EXPR>"<"{RGX_SYMBOL} |
353<S_EXPR>"<"[0-9] {
354 /*
355 * Variable reference -- lookup the variable and return a
356 * pointer to it. Referencing undefined variables is an error.
357 */
358 yylval.l_var = mdb_nv_lookup(&mdb.m_nv, &yytext[1]);
359
360 if (yylval.l_var == NULL)
361 yyerror("variable '%s' is not defined", &yytext[1]);
362
363 return (MDB_TOK_VAR_REF);
364 }
365
366<S_INITIAL>"<<" |
367<S_EXPR>"<<" return (MDB_TOK_LSHIFT); /* Logical shift left operator */
368
369<S_INITIAL>">>" |
370<S_EXPR>">>" return (MDB_TOK_RSHIFT); /* Logical shift right operator */
371
372<S_INITIAL>"*/"[a-zA-Z0-9]"/" |
373<S_EXPR>"*/"[a-zA-Z0-9]"/" {
374 switch (yytext[2]) {
375 case 'c': case '1':
376 return (MDB_TOK_COR1_DEREF);
377 case 's': case '2':
378 return (MDB_TOK_COR2_DEREF);
379 case 'i': case '4':
380#ifdef _ILP32
381 case 'l':
382#endif
383 return (MDB_TOK_COR4_DEREF);
384#ifdef _LP64
385 case 'l':
386#endif
387 case '8':
388 return (MDB_TOK_COR8_DEREF);
389 }
390 yyerror("invalid cast -- %s\n", yytext);
391 }
392
393<S_INITIAL>"%/"[a-zA-Z0-9]"/" |
394<S_EXPR>"%/"[a-zA-Z0-9]"/" {
395 switch (yytext[2]) {
396 case 'c': case '1':
397 return (MDB_TOK_OBJ1_DEREF);
398 case 's': case '2':
399 return (MDB_TOK_OBJ2_DEREF);
400 case 'i': case '4':
401#ifdef _ILP32
402 case 'l':
403#endif
404 return (MDB_TOK_OBJ4_DEREF);
405#ifdef _LP64
406 case 'l':
407#endif
408 case '8':
409 return (MDB_TOK_OBJ8_DEREF);
410 }
411 yyerror("invalid cast -- %s\n", yytext);
412 }
413
414<S_INITIAL>0[iI][0-1]+ |
415<S_EXPR>0[iI][0-1]+ {
416 /*
417 * Binary immediate value.
418 */
Yuri Pankov45851302017-06-12 20:16:28 -0700419 yylval.l_immediate = mdb_strtonum(yytext + 2, 2);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700420 return (MDB_TOK_IMMEDIATE);
421 }
422
423<S_INITIAL>0[oO][0-7]+ |
424<S_EXPR>0[oO][0-7]+ {
425 /*
426 * Octal immediate value.
427 */
Yuri Pankov45851302017-06-12 20:16:28 -0700428 yylval.l_immediate = mdb_strtonum(yytext + 2, 8);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700429 return (MDB_TOK_IMMEDIATE);
430 }
431
432<S_INITIAL>0[tT][0-9]+"."[0-9]+ |
433<S_EXPR>0[tT][0-9]+"."[0-9]+ {
434#ifdef _KMDB
435 yyerror("floating point not supported\n");
436#else
437 /*
438 * Decimal floating point value.
439 */
440 char *p, c;
441 double d;
442 int i;
443
444 if ((p = strsplit(yytext, '.')) == NULL)
445 yyerror("internal scanning error -- expected '.'\n");
446
Yuri Pankov45851302017-06-12 20:16:28 -0700447 d = (double)mdb_strtonum(yytext + 2, 10);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700448
449 for (i = 0; (c = *p++) != '\0'; i++)
450 d = d * 10 + c - '0';
451
452 while (i-- != 0)
453 d /= 10;
454
455 yylval.l_immediate = *((uintmax_t *)&d);
456 return (MDB_TOK_IMMEDIATE);
457#endif
458 }
459
460<S_INITIAL>0[tT][0-9]+ |
461<S_EXPR>0[tT][0-9]+ {
462 /*
463 * Decimal immediate value.
464 */
Yuri Pankov45851302017-06-12 20:16:28 -0700465 yylval.l_immediate = mdb_strtonum(yytext + 2, 10);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700466 return (MDB_TOK_IMMEDIATE);
467 }
468
469<S_INITIAL>0[xX][0-9a-fA-F]+ |
470<S_EXPR>0[xX][0-9a-fA-F]+ {
471 /*
472 * Hexadecimal value.
473 */
Yuri Pankov45851302017-06-12 20:16:28 -0700474 yylval.l_immediate = mdb_strtonum(yytext + 2, 16);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700475 return (MDB_TOK_IMMEDIATE);
476 }
477
478<S_INITIAL>[0-9a-fA-F]+ |
479<S_EXPR>[0-9a-fA-F]+ {
480 GElf_Sym sym;
481 /*
482 * Immediate values without an explicit base are converted
483 * using the default radix (user configurable). However, if
484 * the token does *not* begin with a digit, it is also a
485 * potential symbol (e.g. "f") so we have to check that first.
486 */
487 if (strchr("0123456789", yytext[0]) == NULL &&
488 mdb_tgt_lookup_by_name(mdb.m_target,
489 MDB_TGT_OBJ_EVERY, yytext, &sym, NULL) == 0)
490 yylval.l_immediate = (uintmax_t)sym.st_value;
491 else
Yuri Pankov45851302017-06-12 20:16:28 -0700492 yylval.l_immediate = mdb_strtonum(yytext, mdb.m_radix);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700493 return (MDB_TOK_IMMEDIATE);
494 }
495
496<S_INITIAL>{RGX_SYMBOL} |
497<S_EXPR>{RGX_SYMBOL} {
498 /*
499 * Symbol -- parser will look up in symbol table.
500 */
501 yylval.l_string = strdup(yytext);
502 return (MDB_TOK_SYMBOL);
503 }
504
505";"|\n {
506 /*
507 * End of command -- return to start state and return literal.
508 */
509 BEGIN(S_INITIAL);
510 return (yytext[0]);
511 }
512
513[ \t] ; /* Ignore whitespace */
514
515. return (yytext[0]); /* Return anything else */
516
517%%
518
519void
520mdb_lex_debug(int i)
521{
522 yydebug = i;
523}
524
525void
526mdb_lex_reset(void)
527{
528 BEGIN(S_INITIAL);
529}
530
531void
532yydiscard(void)
533{
534 int c;
535
536 /*
537 * If stdin is a string, pipeline, or tty, throw away all our buffered
538 * data. Otherwise discard characters up to the next likely delimiter.
539 */
540 if (mdb_iob_isastr(mdb.m_in) || mdb_iob_isatty(mdb.m_in) ||
541 mdb_iob_isapipe(mdb.m_in))
542 mdb_iob_discard(mdb.m_in);
543 else {
544 while ((c = mdb_iob_getc(mdb.m_in)) != (int)EOF) {
545 if (c == ';' || c == '\n')
546 break;
547 }
548 }
549
550 BEGIN(S_INITIAL);
551}
552
553static void
554yyerror_reset(void)
555{
556 yydiscard();
557 mdb_argvec_reset(&mdb.m_frame->f_argvec);
558 longjmp(mdb.m_frame->f_pcb, MDB_ERR_PARSE);
559}
560
561void
562yyerror(const char *format, ...)
563{
564 va_list alist;
565 char *s;
566
567 mdb_iob_printf(mdb.m_err, "%s: ", mdb.m_pname);
568 va_start(alist, format);
569 mdb_iob_vprintf(mdb.m_err, format, alist);
570 va_end(alist);
571
572 if (strchr(format, '\n') == NULL) {
573 if (!mdb_iob_isatty(mdb.m_in)) {
574 mdb_iob_printf(mdb.m_err, " on line %d of %s",
575 yylineno, mdb_iob_name(mdb.m_in));
576 }
577
578 s = strchr2esc(yytext, strlen(yytext));
579 mdb_iob_printf(mdb.m_err, " near \"%s\"\n", s);
580 strfree(s);
581 }
582
583 yyerror_reset();
584}
585
586void
587yyperror(const char *format, ...)
588{
589 va_list alist;
590
591 va_start(alist, format);
592 vwarn(format, alist);
593 va_end(alist);
594
595 yyerror_reset();
596}
597
598int
599yywrap(void)
600{
601 mdb_dprintf(MDB_DBG_PARSER, "yywrap at line %d\n", yylineno);
602 return (1); /* indicate that lex should return a zero token for EOF */
603}
604
605/*PRINTFLIKE2*/
606/*ARGSUSED*/
607int
608yyfprintf(FILE *stream, const char *format, ...)
609{
610 va_list alist;
611
612 va_start(alist, format);
613 mdb_iob_vprintf(mdb.m_err, format, alist);
614 va_end(alist);
615 return (0);
616}
617
618/*PRINTFLIKE1*/
619int
620yyprintf(const char *format, ...)
621{
622 va_list alist;
623
624 va_start(alist, format);
625 mdb_iob_vprintf(mdb.m_err, format, alist);
626 va_end(alist);
627 return (0);
628}
629
630static int
631input(void)
632{
633 int c = mdb_iob_getc(mdb.m_in);
634
635 if (c == '\n')
636 yylineno++;
637
638 return (c == EOF ? 0 : c);
639}
640
641static void
642unput(int c)
643{
644 if (c == '\n')
645 yylineno--;
646
647 (void) mdb_iob_ungetc(mdb.m_in, c == 0 ? EOF : c);
648}
649
650static void
651output(int c)
652{
653 char ch = c;
654 mdb_iob_nputs(mdb.m_out, &ch, sizeof (ch));
655}
656
657static char *
658string_nextquote(char *s, char q1, char q2)
659{
660 char c = 0;
661
662 do {
663 if (c != '\\' && (*s == q1 || *s == q2))
664 return (s);
665 } while ((c = *s++) != '\0');
666
667 return (NULL);
668}
669
670static void
671string_unquote(char *s)
672{
673 char *o, *p, *q, c;
674
675 for (o = p = s; (p = string_nextquote(p, '\'', '"')) != NULL; o = p) {
676 /*
677 * If the quote wasn't the first character, advance
678 * the destination buffer past what we skipped.
679 */
680 if (p > o) {
Alexander Eremina11593b2011-05-17 12:36:01 -0400681 /* Using memmove to prevent possible overlap. */
682 (void) memmove(s, o, p - o);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700683 s += p - o;
684 }
685
686 c = *p; /* Save the current quote */
687
688 /*
689 * Look ahead and find the matching quote. If none is
690 * found, use yyerror to longjmp out of the lexer.
691 */
692 if (c == '"')
693 q = string_nextquote(p + 1, c, c);
694 else
695 q = strchr(p + 1, c);
696
697 if (q == NULL)
698 yyerror("syntax error: %c unmatched", c);
699
700 /*
701 * If the string is non-empty, copy it to the destination
702 * and convert escape sequences if *p is double-quote.
703 */
704 if (q > p + 1) {
Alexander Eremina11593b2011-05-17 12:36:01 -0400705 (void) memmove(s, p + 1, q - p - 1);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700706 if (c == '"') {
707 s[q - p - 1] = '\0';
708 s += stresc2chr(s);
709 } else
710 s += q - p - 1;
711 }
712
713 p = q + 1; /* Advance p past matching quote */
714 }
715
Alexander Eremina11593b2011-05-17 12:36:01 -0400716 (void) memmove(s, o, strlen(o) + 1);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700717}
718
719/*
720 * Unfortunately, lex and yacc produces code that is inherently global. They do
721 * not provide routines to save and restore state, instead relying on global
722 * variables. There is one single lex state, so that if a frame switch then
723 * tries to perform any evaluation, the old values are corrupted. This
724 * structure and corresponding function provide a means of preserving lex state
725 * across frame switches. Note that this is tied to the lex implementation, so
726 * if the lex compiler is changed or upgraded to a different format, then this
727 * may need to be altered. This is unavoidable due to the implementation of lex
728 * and yacc. This is essentially a collection of all the global variables
729 * defined by the lex code, excluding those that do not change through the
730 * course of yylex() and yyparse().
731 */
732extern struct yysvf *yylstate[], **yylsp, **yyolsp; extern int yyprevious;
733extern int *yyfnd;
734
735extern YYSTYPE *yypv;
736extern int *yyps;
737extern int yytmp;
738extern int yystate;
739extern int yynerrs;
740extern int yyerrflag;
741extern int yychar;
742extern YYSTYPE yylval;
743extern YYSTYPE yyval;
744extern int *yys;
745extern YYSTYPE *yyv;
746
747typedef struct mdb_lex_state {
748 /* Variables needed by yylex */
749 int yyleng;
750 char yytext[YYLMAX];
751 int yymorfg;
752 int yylineno;
753 void *yyestate;
754 void *yylstate[BUFSIZ];
755 void *yylsp;
756 void *yyolsp;
757 int *yyfnd;
758 int yyprevious;
759 void *yybgin;
760 /* Variables needed by yyparse */
761 void *yypv;
762 int *yyps;
763 int yytmp;
764 int yystate;
765 int yynerrs;
766 int yyerrflag;
767 int yychar;
768 YYSTYPE yylval;
769 YYSTYPE yyval;
770 int yys[YYMAXDEPTH];
771 YYSTYPE yyv[YYMAXDEPTH];
772} mdb_lex_state_t;
773
774void
775mdb_lex_state_save(mdb_lex_state_t *s)
776{
777 ASSERT(s != NULL);
778
779 s->yyleng = yyleng;
780 s->yymorfg = yymorfg;
781 s->yylineno = yylineno;
782 s->yyestate = yyestate;
783 bcopy(yylstate, s->yylstate, YYLMAX * sizeof (void *));
784 s->yylsp = yylsp;
785 s->yyolsp = yyolsp;
786 s->yyfnd = yyfnd;
787 s->yyprevious = yyprevious;
788 s->yybgin = yybgin;
789
790 s->yypv = yypv;
791 s->yyps = yyps;
792 s->yystate = yystate;
793 s->yytmp = yytmp;
794 s->yynerrs = yynerrs;
795 s->yyerrflag = yyerrflag;
796 s->yychar = yychar;
797 s->yylval = yylval;
798 s->yyval = yyval;
799}
800
801void
802mdb_lex_state_restore(mdb_lex_state_t *s)
803{
804 ASSERT(s != NULL);
805
806 yyleng = s->yyleng;
807 yytext = s->yytext;
808 yymorfg = s->yymorfg;
809 yylineno = s->yylineno;
810 yyestate = s->yyestate;
811 bcopy(s->yylstate, yylstate, YYLMAX * sizeof (void *));
812 yylsp = s->yylsp;
813 yyolsp = s->yyolsp;
814 yyfnd = s->yyfnd;
815 yyprevious = s->yyprevious;
816 yybgin = s->yybgin;
817
818 yypv = s->yypv;
819 yyps = s->yyps;
820 yystate = s->yystate;
821 yytmp = s->yytmp;
822 yynerrs = s->yynerrs;
823 yyerrflag = s->yyerrflag;
824 yychar = s->yychar;
825 yylval = s->yylval;
826 yyval = s->yyval;
827 yys = s->yys;
828 yyv = s->yyv;
829}
830
831/*
832 * Create and initialize the lex/yacc-specific state associated with a frame
833 * structure. We set all fields to known safe values so that
834 * mdb_lex_state_restore() can be used safely before mdb_lex_state_save().
835 */
836void
837mdb_lex_state_create(mdb_frame_t *f)
838{
839 f->f_lstate = mdb_alloc(sizeof (mdb_lex_state_t), UM_SLEEP);
840
841 yyleng = 0;
842 yymorfg = 0;
843 /* yytext is fine with garbage in it */
844 yytext = f->f_lstate->yytext;
845 yylineno = 1;
846 yyestate = NULL;
847 bzero(yylstate, YYLMAX * sizeof (void *));
848 yylsp = NULL;
849 yyolsp = NULL;
850 yyfnd = 0;
851 yyprevious = YYNEWLINE;
852 yys = f->f_lstate->yys;
853 yyv = f->f_lstate->yyv;
854 mdb_argvec_create(&f->f_argvec);
855 f->f_oldstate = 0;
856 mdb_lex_reset(); /* Responsible for setting yybgin */
857}
858
859void
860mdb_lex_state_destroy(mdb_frame_t *f)
861{
862 mdb_free(f->f_lstate, sizeof (mdb_lex_state_t));
863 f->f_lstate = NULL;
864 mdb_argvec_destroy(&f->f_argvec);
865}