Annotation of src/usr.bin/lex/parse.y, Revision 1.7
1.7 ! deraadt 1: /* $OpenBSD: parse.y,v 1.5 2002/05/30 10:53:45 deraadt Exp $ */
1.2 deraadt 2:
1.1 deraadt 3: /* parse.y - parser for flex input */
4:
5: %token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
6: %token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS
7:
8: %token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
9: %token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
10:
11: %{
12: /*-
13: * Copyright (c) 1990 The Regents of the University of California.
14: * All rights reserved.
15: *
16: * This code is derived from software contributed to Berkeley by
17: * Vern Paxson.
18: *
19: * The United States Government has rights in this work pursuant
20: * to contract no. DE-AC03-76SF00098 between the United States
21: * Department of Energy and the University of California.
22: *
1.4 deraadt 23: * Redistribution and use in source and binary forms, with or without
24: * modification, are permitted provided that: (1) source distributions
25: * retain this entire copyright notice and comment, and (2) distributions
26: * including binaries display the following acknowledgement: ``This product
27: * includes software developed by the University of California, Berkeley
28: * and its contributors'' in the documentation or other materials provided
29: * with the distribution and in all advertising materials mentioning
30: * features or use of this software. Neither the name of the University nor
31: * the names of its contributors may be used to endorse or promote products
32: * derived from this software without specific prior written permission.
1.1 deraadt 33: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
34: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
35: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
36: */
37:
1.7 ! deraadt 38: /* $Header: /cvs/src/usr.bin/lex/parse.y,v 1.5 2002/05/30 10:53:45 deraadt Exp $ */
1.1 deraadt 39:
40:
41: /* Some versions of bison are broken in that they use alloca() but don't
42: * declare it properly. The following is the patented (just kidding!)
43: * #ifdef chud to fix the problem, courtesy of Francois Pinard.
44: */
45: #ifdef YYBISON
46: /* AIX requires this to be the first thing in the file. What a piece. */
47: # ifdef _AIX
48: #pragma alloca
49: # endif
50: #endif
51:
52: #include "flexdef.h"
53:
54: /* The remainder of the alloca() cruft has to come after including flexdef.h,
55: * so HAVE_ALLOCA_H is (possibly) defined.
56: */
57: #ifdef YYBISON
58: # ifdef __GNUC__
59: # ifndef alloca
60: # define alloca __builtin_alloca
61: # endif
62: # else
63: # if HAVE_ALLOCA_H
64: # include <alloca.h>
65: # else
66: # ifdef __hpux
67: void *alloca ();
68: # else
69: # ifdef __TURBOC__
70: # include <malloc.h>
71: # else
72: char *alloca ();
73: # endif
74: # endif
75: # endif
76: # endif
77: #endif
78:
79: /* Bletch, ^^^^ that was ugly! */
80:
81:
82: int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, rulelen;
83: int trlcontxt, xcluflg, currccl, cclsorted, varlength, variable_trail_rule;
84:
85: int *scon_stk;
86: int scon_stk_ptr;
87:
88: static int madeany = false; /* whether we've made the '.' character class */
89: int previous_continued_action; /* whether the previous rule's action was '|' */
90:
91: /* Expand a POSIX character class expression. */
92: #define CCL_EXPR(func) \
93: { \
94: int c; \
95: for ( c = 0; c < csize; ++c ) \
96: if ( isascii(c) && func(c) ) \
97: ccladd( currccl, c ); \
98: }
99:
100: /* While POSIX defines isblank(), it's not ANSI C. */
101: #define IS_BLANK(c) ((c) == ' ' || (c) == '\t')
102:
103: /* On some over-ambitious machines, such as DEC Alpha's, the default
104: * token type is "long" instead of "int"; this leads to problems with
105: * declaring yylval in flexdef.h. But so far, all the yacc's I've seen
106: * wrap their definitions of YYSTYPE with "#ifndef YYSTYPE"'s, so the
107: * following should ensure that the default token type is "int".
108: */
109: #define YYSTYPE int
110:
111: %}
112:
113: %%
114: goal : initlex sect1 sect1end sect2 initforrule
115: { /* add default rule */
116: int def_rule;
117:
118: pat = cclinit();
119: cclnegate( pat );
120:
121: def_rule = mkstate( -pat );
122:
123: /* Remember the number of the default rule so we
124: * don't generate "can't match" warnings for it.
125: */
126: default_rule = num_rules;
127:
128: finish_rule( def_rule, false, 0, 0 );
129:
130: for ( i = 1; i <= lastsc; ++i )
131: scset[i] = mkbranch( scset[i], def_rule );
132:
133: if ( spprdflt )
134: add_action(
135: "YY_FATAL_ERROR( \"flex scanner jammed\" )" );
136: else
137: add_action( "ECHO" );
138:
139: add_action( ";\n\tYY_BREAK\n" );
140: }
141: ;
142:
143: initlex :
144: { /* initialize for processing rules */
145:
146: /* Create default DFA start condition. */
147: scinstal( "INITIAL", false );
148: }
149: ;
150:
151: sect1 : sect1 startconddecl namelist1
152: | sect1 options
153: |
154: | error
155: { synerr( "unknown error processing section 1" ); }
156: ;
157:
158: sect1end : SECTEND
159: {
160: check_options();
161: scon_stk = allocate_integer_array( lastsc + 1 );
162: scon_stk_ptr = 0;
163: }
164: ;
165:
166: startconddecl : SCDECL
167: { xcluflg = false; }
168:
169: | XSCDECL
170: { xcluflg = true; }
171: ;
172:
173: namelist1 : namelist1 NAME
174: { scinstal( nmstr, xcluflg ); }
175:
176: | NAME
177: { scinstal( nmstr, xcluflg ); }
178:
179: | error
180: { synerr( "bad start condition list" ); }
181: ;
182:
183: options : OPTION_OP optionlist
184: ;
185:
186: optionlist : optionlist option
187: |
188: ;
189:
190: option : OPT_OUTFILE '=' NAME
191: {
192: outfilename = copy_string( nmstr );
193: did_outfilename = 1;
194: }
195: | OPT_PREFIX '=' NAME
196: { prefix = copy_string( nmstr ); }
197: | OPT_YYCLASS '=' NAME
198: { yyclass = copy_string( nmstr ); }
199: ;
200:
201: sect2 : sect2 scon initforrule flexrule '\n'
202: { scon_stk_ptr = $2; }
203: | sect2 scon '{' sect2 '}'
204: { scon_stk_ptr = $2; }
205: |
206: ;
207:
208: initforrule :
209: {
210: /* Initialize for a parse of one rule. */
211: trlcontxt = variable_trail_rule = varlength = false;
212: trailcnt = headcnt = rulelen = 0;
213: current_state_type = STATE_NORMAL;
214: previous_continued_action = continued_action;
215: in_rule = true;
216:
217: new_rule();
218: }
219: ;
220:
221: flexrule : '^' rule
222: {
223: pat = $2;
224: finish_rule( pat, variable_trail_rule,
225: headcnt, trailcnt );
226:
227: if ( scon_stk_ptr > 0 )
228: {
229: for ( i = 1; i <= scon_stk_ptr; ++i )
230: scbol[scon_stk[i]] =
231: mkbranch( scbol[scon_stk[i]],
232: pat );
233: }
234:
235: else
236: {
237: /* Add to all non-exclusive start conditions,
238: * including the default (0) start condition.
239: */
240:
241: for ( i = 1; i <= lastsc; ++i )
242: if ( ! scxclu[i] )
243: scbol[i] = mkbranch( scbol[i],
244: pat );
245: }
246:
247: if ( ! bol_needed )
248: {
249: bol_needed = true;
250:
251: if ( performance_report > 1 )
252: pinpoint_message(
253: "'^' operator results in sub-optimal performance" );
254: }
255: }
256:
257: | rule
258: {
259: pat = $1;
260: finish_rule( pat, variable_trail_rule,
261: headcnt, trailcnt );
262:
263: if ( scon_stk_ptr > 0 )
264: {
265: for ( i = 1; i <= scon_stk_ptr; ++i )
266: scset[scon_stk[i]] =
267: mkbranch( scset[scon_stk[i]],
268: pat );
269: }
270:
271: else
272: {
273: for ( i = 1; i <= lastsc; ++i )
274: if ( ! scxclu[i] )
275: scset[i] =
276: mkbranch( scset[i],
277: pat );
278: }
279: }
280:
281: | EOF_OP
282: {
283: if ( scon_stk_ptr > 0 )
284: build_eof_action();
285:
286: else
287: {
288: /* This EOF applies to all start conditions
289: * which don't already have EOF actions.
290: */
291: for ( i = 1; i <= lastsc; ++i )
292: if ( ! sceof[i] )
293: scon_stk[++scon_stk_ptr] = i;
294:
295: if ( scon_stk_ptr == 0 )
296: warn(
297: "all start conditions already have <<EOF>> rules" );
298:
299: else
300: build_eof_action();
301: }
302: }
303:
304: | error
305: { synerr( "unrecognized rule" ); }
306: ;
307:
308: scon_stk_ptr :
309: { $$ = scon_stk_ptr; }
310: ;
311:
312: scon : '<' scon_stk_ptr namelist2 '>'
313: { $$ = $2; }
314:
315: | '<' '*' '>'
316: {
317: $$ = scon_stk_ptr;
318:
319: for ( i = 1; i <= lastsc; ++i )
320: {
321: int j;
322:
323: for ( j = 1; j <= scon_stk_ptr; ++j )
324: if ( scon_stk[j] == i )
325: break;
326:
327: if ( j > scon_stk_ptr )
328: scon_stk[++scon_stk_ptr] = i;
329: }
330: }
331:
332: |
333: { $$ = scon_stk_ptr; }
334: ;
335:
336: namelist2 : namelist2 ',' sconname
337:
338: | sconname
339:
340: | error
341: { synerr( "bad start condition list" ); }
342: ;
343:
344: sconname : NAME
345: {
346: if ( (scnum = sclookup( nmstr )) == 0 )
347: format_pinpoint_message(
348: "undeclared start condition %s",
349: nmstr );
350: else
351: {
352: for ( i = 1; i <= scon_stk_ptr; ++i )
353: if ( scon_stk[i] == scnum )
354: {
355: format_warn(
356: "<%s> specified twice",
357: scname[scnum] );
358: break;
359: }
360:
361: if ( i > scon_stk_ptr )
362: scon_stk[++scon_stk_ptr] = scnum;
363: }
364: }
365: ;
366:
367: rule : re2 re
368: {
369: if ( transchar[lastst[$2]] != SYM_EPSILON )
370: /* Provide final transition \now/ so it
371: * will be marked as a trailing context
372: * state.
373: */
374: $2 = link_machines( $2,
375: mkstate( SYM_EPSILON ) );
376:
377: mark_beginning_as_normal( $2 );
378: current_state_type = STATE_NORMAL;
379:
380: if ( previous_continued_action )
381: {
382: /* We need to treat this as variable trailing
383: * context so that the backup does not happen
384: * in the action but before the action switch
385: * statement. If the backup happens in the
386: * action, then the rules "falling into" this
387: * one's action will *also* do the backup,
388: * erroneously.
389: */
390: if ( ! varlength || headcnt != 0 )
391: warn(
392: "trailing context made variable due to preceding '|' action" );
393:
394: /* Mark as variable. */
395: varlength = true;
396: headcnt = 0;
397: }
398:
399: if ( lex_compat || (varlength && headcnt == 0) )
400: { /* variable trailing context rule */
401: /* Mark the first part of the rule as the
402: * accepting "head" part of a trailing
403: * context rule.
404: *
405: * By the way, we didn't do this at the
406: * beginning of this production because back
407: * then current_state_type was set up for a
408: * trail rule, and add_accept() can create
409: * a new state ...
410: */
411: add_accept( $1,
412: num_rules | YY_TRAILING_HEAD_MASK );
413: variable_trail_rule = true;
414: }
415:
416: else
417: trailcnt = rulelen;
418:
419: $$ = link_machines( $1, $2 );
420: }
421:
422: | re2 re '$'
423: { synerr( "trailing context used twice" ); }
424:
425: | re '$'
426: {
427: headcnt = 0;
428: trailcnt = 1;
429: rulelen = 1;
430: varlength = false;
431:
432: current_state_type = STATE_TRAILING_CONTEXT;
433:
434: if ( trlcontxt )
435: {
436: synerr( "trailing context used twice" );
437: $$ = mkstate( SYM_EPSILON );
438: }
439:
440: else if ( previous_continued_action )
441: {
442: /* See the comment in the rule for "re2 re"
443: * above.
444: */
445: warn(
446: "trailing context made variable due to preceding '|' action" );
447:
448: varlength = true;
449: }
450:
451: if ( lex_compat || varlength )
452: {
453: /* Again, see the comment in the rule for
454: * "re2 re" above.
455: */
456: add_accept( $1,
457: num_rules | YY_TRAILING_HEAD_MASK );
458: variable_trail_rule = true;
459: }
460:
461: trlcontxt = true;
462:
463: eps = mkstate( SYM_EPSILON );
464: $$ = link_machines( $1,
465: link_machines( eps, mkstate( '\n' ) ) );
466: }
467:
468: | re
469: {
470: $$ = $1;
471:
472: if ( trlcontxt )
473: {
474: if ( lex_compat || (varlength && headcnt == 0) )
475: /* Both head and trail are
476: * variable-length.
477: */
478: variable_trail_rule = true;
479: else
480: trailcnt = rulelen;
481: }
482: }
483: ;
484:
485:
486: re : re '|' series
487: {
488: varlength = true;
489: $$ = mkor( $1, $3 );
490: }
491:
492: | series
493: { $$ = $1; }
494: ;
495:
496:
497: re2 : re '/'
498: {
499: /* This rule is written separately so the
500: * reduction will occur before the trailing
501: * series is parsed.
502: */
503:
504: if ( trlcontxt )
505: synerr( "trailing context used twice" );
506: else
507: trlcontxt = true;
508:
509: if ( varlength )
510: /* We hope the trailing context is
511: * fixed-length.
512: */
513: varlength = false;
514: else
515: headcnt = rulelen;
516:
517: rulelen = 0;
518:
519: current_state_type = STATE_TRAILING_CONTEXT;
520: $$ = $1;
521: }
522: ;
523:
524: series : series singleton
525: {
526: /* This is where concatenation of adjacent patterns
527: * gets done.
528: */
529: $$ = link_machines( $1, $2 );
530: }
531:
532: | singleton
533: { $$ = $1; }
534: ;
535:
536: singleton : singleton '*'
537: {
538: varlength = true;
539:
540: $$ = mkclos( $1 );
541: }
542:
543: | singleton '+'
544: {
545: varlength = true;
546: $$ = mkposcl( $1 );
547: }
548:
549: | singleton '?'
550: {
551: varlength = true;
552: $$ = mkopt( $1 );
553: }
554:
555: | singleton '{' NUMBER ',' NUMBER '}'
556: {
557: varlength = true;
558:
559: if ( $3 > $5 || $3 < 0 )
560: {
561: synerr( "bad iteration values" );
562: $$ = $1;
563: }
564: else
565: {
566: if ( $3 == 0 )
567: {
568: if ( $5 <= 0 )
569: {
570: synerr(
571: "bad iteration values" );
572: $$ = $1;
573: }
574: else
575: $$ = mkopt(
576: mkrep( $1, 1, $5 ) );
577: }
578: else
579: $$ = mkrep( $1, $3, $5 );
580: }
581: }
582:
583: | singleton '{' NUMBER ',' '}'
584: {
585: varlength = true;
586:
587: if ( $3 <= 0 )
588: {
589: synerr( "iteration value must be positive" );
590: $$ = $1;
591: }
592:
593: else
594: $$ = mkrep( $1, $3, INFINITY );
595: }
596:
597: | singleton '{' NUMBER '}'
598: {
599: /* The singleton could be something like "(foo)",
600: * in which case we have no idea what its length
601: * is, so we punt here.
602: */
603: varlength = true;
604:
605: if ( $3 <= 0 )
606: {
607: synerr( "iteration value must be positive" );
608: $$ = $1;
609: }
610:
611: else
612: $$ = link_machines( $1,
613: copysingl( $1, $3 - 1 ) );
614: }
615:
616: | '.'
617: {
618: if ( ! madeany )
619: {
620: /* Create the '.' character class. */
621: anyccl = cclinit();
622: ccladd( anyccl, '\n' );
623: cclnegate( anyccl );
624:
625: if ( useecs )
626: mkeccl( ccltbl + cclmap[anyccl],
627: ccllen[anyccl], nextecm,
628: ecgroup, csize, csize );
629:
630: madeany = true;
631: }
632:
633: ++rulelen;
634:
635: $$ = mkstate( -anyccl );
636: }
637:
638: | fullccl
639: {
640: if ( ! cclsorted )
641: /* Sort characters for fast searching. We
642: * use a shell sort since this list could
643: * be large.
644: */
645: cshell( ccltbl + cclmap[$1], ccllen[$1], true );
646:
647: if ( useecs )
648: mkeccl( ccltbl + cclmap[$1], ccllen[$1],
649: nextecm, ecgroup, csize, csize );
650:
651: ++rulelen;
652:
653: $$ = mkstate( -$1 );
654: }
655:
656: | PREVCCL
657: {
658: ++rulelen;
659:
660: $$ = mkstate( -$1 );
661: }
662:
663: | '"' string '"'
664: { $$ = $2; }
665:
666: | '(' re ')'
667: { $$ = $2; }
668:
669: | CHAR
670: {
671: ++rulelen;
672:
673: if ( caseins && $1 >= 'A' && $1 <= 'Z' )
674: $1 = clower( $1 );
675:
676: $$ = mkstate( $1 );
677: }
678: ;
679:
680: fullccl : '[' ccl ']'
681: { $$ = $2; }
682:
683: | '[' '^' ccl ']'
684: {
685: cclnegate( $3 );
686: $$ = $3;
687: }
688: ;
689:
690: ccl : ccl CHAR '-' CHAR
691: {
692: if ( caseins )
693: {
694: if ( $2 >= 'A' && $2 <= 'Z' )
695: $2 = clower( $2 );
696: if ( $4 >= 'A' && $4 <= 'Z' )
697: $4 = clower( $4 );
698: }
699:
700: if ( $2 > $4 )
701: synerr( "negative range in character class" );
702:
703: else
704: {
705: for ( i = $2; i <= $4; ++i )
706: ccladd( $1, i );
707:
708: /* Keep track if this ccl is staying in
709: * alphabetical order.
710: */
711: cclsorted = cclsorted && ($2 > lastchar);
712: lastchar = $4;
713: }
714:
715: $$ = $1;
716: }
717:
718: | ccl CHAR
719: {
720: if ( caseins && $2 >= 'A' && $2 <= 'Z' )
721: $2 = clower( $2 );
722:
723: ccladd( $1, $2 );
724: cclsorted = cclsorted && ($2 > lastchar);
725: lastchar = $2;
726: $$ = $1;
727: }
728:
729: | ccl ccl_expr
730: {
731: /* Too hard to properly maintain cclsorted. */
732: cclsorted = false;
733: $$ = $1;
734: }
735:
736: |
737: {
738: cclsorted = true;
739: lastchar = 0;
740: currccl = $$ = cclinit();
741: }
742: ;
743:
744: ccl_expr: CCE_ALNUM { CCL_EXPR(isalnum) }
745: | CCE_ALPHA { CCL_EXPR(isalpha) }
746: | CCE_BLANK { CCL_EXPR(IS_BLANK) }
747: | CCE_CNTRL { CCL_EXPR(iscntrl) }
748: | CCE_DIGIT { CCL_EXPR(isdigit) }
749: | CCE_GRAPH { CCL_EXPR(isgraph) }
750: | CCE_LOWER { CCL_EXPR(islower) }
751: | CCE_PRINT { CCL_EXPR(isprint) }
752: | CCE_PUNCT { CCL_EXPR(ispunct) }
753: | CCE_SPACE { CCL_EXPR(isspace) }
754: | CCE_UPPER {
755: if ( caseins )
756: CCL_EXPR(islower)
757: else
758: CCL_EXPR(isupper)
759: }
760: | CCE_XDIGIT { CCL_EXPR(isxdigit) }
761: ;
762:
763: string : string CHAR
764: {
765: if ( caseins && $2 >= 'A' && $2 <= 'Z' )
766: $2 = clower( $2 );
767:
768: ++rulelen;
769:
770: $$ = link_machines( $1, mkstate( $2 ) );
771: }
772:
773: |
774: { $$ = mkstate( SYM_EPSILON ); }
775: ;
776:
777: %%
778:
779:
780: /* build_eof_action - build the "<<EOF>>" action for the active start
781: * conditions
782: */
783:
784: void build_eof_action()
785: {
786: register int i;
787: char action_text[MAXLINE];
788:
789: for ( i = 1; i <= scon_stk_ptr; ++i )
790: {
791: if ( sceof[scon_stk[i]] )
792: format_pinpoint_message(
793: "multiple <<EOF>> rules for start condition %s",
794: scname[scon_stk[i]] );
795:
796: else
797: {
798: sceof[scon_stk[i]] = true;
1.7 ! deraadt 799: snprintf( action_text, sizeof action_text,
! 800: "case YY_STATE_EOF(%s):\n",
1.1 deraadt 801: scname[scon_stk[i]] );
802: add_action( action_text );
803: }
804: }
805:
806: line_directive_out( (FILE *) 0, 1 );
807:
808: /* This isn't a normal rule after all - don't count it as
809: * such, so we don't have any holes in the rule numbering
810: * (which make generating "rule can never match" warnings
811: * more difficult.
812: */
813: --num_rules;
814: ++num_eof_rules;
815: }
816:
817:
818: /* format_synerr - write out formatted syntax error */
819:
820: void format_synerr( msg, arg )
821: char msg[], arg[];
822: {
823: char errmsg[MAXLINE];
824:
1.7 ! deraadt 825: (void) snprintf( errmsg, sizeof errmsg, msg, arg );
1.1 deraadt 826: synerr( errmsg );
827: }
828:
829:
830: /* synerr - report a syntax error */
831:
832: void synerr( str )
833: char str[];
834: {
835: syntaxerror = true;
836: pinpoint_message( str );
837: }
838:
839:
840: /* format_warn - write out formatted warning */
841:
842: void format_warn( msg, arg )
843: char msg[], arg[];
844: {
845: char warn_msg[MAXLINE];
846:
1.7 ! deraadt 847: (void) snprintf( warn_msg, sizeof warn_msg, msg, arg );
1.1 deraadt 848: warn( warn_msg );
849: }
850:
851:
852: /* warn - report a warning, unless -w was given */
853:
854: void warn( str )
855: char str[];
856: {
857: line_warning( str, linenum );
858: }
859:
860: /* format_pinpoint_message - write out a message formatted with one string,
861: * pinpointing its location
862: */
863:
864: void format_pinpoint_message( msg, arg )
865: char msg[], arg[];
866: {
867: char errmsg[MAXLINE];
868:
1.7 ! deraadt 869: (void) snprintf( errmsg, sizeof errmsg, msg, arg );
1.1 deraadt 870: pinpoint_message( errmsg );
871: }
872:
873:
874: /* pinpoint_message - write out a message, pinpointing its location */
875:
876: void pinpoint_message( str )
877: char str[];
878: {
879: line_pinpoint( str, linenum );
880: }
881:
882:
883: /* line_warning - report a warning at a given line, unless -w was given */
884:
885: void line_warning( str, line )
886: char str[];
887: int line;
888: {
889: char warning[MAXLINE];
890:
891: if ( ! nowarn )
892: {
1.7 ! deraadt 893: snprintf( warning, sizeof warning, "warning, %s", str );
1.1 deraadt 894: line_pinpoint( warning, line );
895: }
896: }
897:
898:
899: /* line_pinpoint - write out a message, pinpointing it at the given line */
900:
901: void line_pinpoint( str, line )
902: char str[];
903: int line;
904: {
905: fprintf( stderr, "\"%s\", line %d: %s\n", infilename, line, str );
906: }
907:
908:
909: /* yyerror - eat up an error message from the parser;
910: * currently, messages are ignore
911: */
912:
913: void yyerror( msg )
914: char msg[];
915: {
916: }