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