Research V7 development
[unix-history] / usr / src / cmd / yacc / y2.c
CommitLineData
f8bd8444
SJ
1# include "dextern"
2# define IDENTIFIER 257
3# define MARK 258
4# define TERM 259
5# define LEFT 260
6# define RIGHT 261
7# define BINARY 262
8# define PREC 263
9# define LCURLY 264
10# define C_IDENTIFIER 265 /* name followed by colon */
11# define NUMBER 266
12# define START 267
13# define TYPEDEF 268
14# define TYPENAME 269
15# define UNION 270
16# define ENDFILE 0
17
18 /* communication variables between various I/O routines */
19
20char *infile; /* input file name */
21int numbval; /* value of an input number */
22char tokname[NAMESIZE]; /* input token name */
23
24 /* storage of names */
25
26char cnames[CNAMSZ]; /* place where token and nonterminal names are stored */
27int cnamsz = CNAMSZ; /* size of cnames */
28char * cnamp = cnames; /* place where next name is to be put in */
29int ndefout = 3; /* number of defined symbols output */
30
31 /* storage of types */
32int ntypes; /* number of types defined */
33char * typeset[NTYPES]; /* pointers to type tags */
34
35 /* symbol tables for tokens and nonterminals */
36
37int ntokens = 0;
38struct toksymb tokset[NTERMS];
39int toklev[NTERMS];
40int nnonter = -1;
41struct ntsymb nontrst[NNONTERM];
42int start; /* start symbol */
43
44 /* assigned token type values */
45int extval = 0;
46
47 /* input and output file descriptors */
48
49FILE * finput; /* yacc input file */
50FILE * faction; /* file for saving actions */
51FILE * fdefine; /* file for # defines */
52FILE * ftable; /* y.tab.c file */
53FILE * ftemp; /* tempfile to pass 2 */
54FILE * foutput; /* y.output file */
55
56 /* storage for grammar rules */
57
58int mem0[MEMSIZE] ; /* production storage */
59int *mem = mem0;
60int nprod= 1; /* number of productions */
61int *prdptr[NPROD]; /* pointers to descriptions of productions */
62int levprd[NPROD] ; /* precedence levels for the productions */
63
64
65setup(argc,argv) int argc; char *argv[];
66{ int i,j,lev,t, ty;
67 int c;
68 int *p;
69 char actname[8];
70
71 foutput = NULL;
72 fdefine = NULL;
73 i = 1;
74 while( argc >= 2 && argv[1][0] == '-' ) {
75 while( *++(argv[1]) ){
76 switch( *argv[1] ){
77 case 'v':
78 case 'V':
79 foutput = fopen(FILEU, "w" );
80 if( foutput == NULL ) error( "cannot open y.output" );
81 continue;
82 case 'D':
83 case 'd':
84 fdefine = fopen( FILED, "w" );
85 continue;
86 case 'o':
87 case 'O':
88 fprintf( stderr, "`o' flag now default in yacc\n" );
89 continue;
90
91 case 'r':
92 case 'R':
93 error( "Ratfor Yacc is dead: sorry...\n" );
94
95 default:
96 error( "illegal option: %c", *argv[1]);
97 }
98 }
99 argv++;
100 argc--;
101 }
102
103 ftable = fopen( OFILE, "w" );
104 if( ftable == NULL ) error( "cannot open table file" );
105
106 ftemp = fopen( TEMPNAME, "w" );
107 faction = fopen( ACTNAME, "w" );
108 if( ftemp==NULL || faction==NULL ) error( "cannot open temp file" );
109
110 if( argc < 2 || ((finput=fopen( infile=argv[1], "r" )) == NULL ) ){
111 error( "cannot open input file" );
112 }
113
114 cnamp = cnames;
115 defin(0,"$end");
116 extval = 0400;
117 defin(0,"error");
118 defin(1,"$accept");
119 mem=mem0;
120 lev = 0;
121 ty = 0;
122 i=0;
123
124 /* sorry -- no yacc parser here.....
125 we must bootstrap somehow... */
126
127 for( t=gettok(); t!=MARK && t!= ENDFILE; ){
128 switch( t ){
129
130 case ';':
131 t = gettok();
132 break;
133
134 case START:
135 if( (t=gettok()) != IDENTIFIER ){
136 error( "bad %%start construction" );
137 }
138 start = chfind(1,tokname);
139 t = gettok();
140 continue;
141
142 case TYPEDEF:
143 if( (t=gettok()) != TYPENAME ) error( "bad syntax in %%type" );
144 ty = numbval;
145 for(;;){
146 t = gettok();
147 switch( t ){
148
149 case IDENTIFIER:
150 if( (t=chfind( 1, tokname ) ) < NTBASE ) {
151 j = TYPE( toklev[t] );
152 if( j!= 0 && j != ty ){
153 error( "type redeclaration of token %s",
154 tokset[t].name );
155 }
156 else SETTYPE( toklev[t],ty);
157 }
158 else {
159 j = nontrst[t-NTBASE].tvalue;
160 if( j != 0 && j != ty ){
161 error( "type redeclaration of nonterminal %s",
162 nontrst[t-NTBASE].name );
163 }
164 else nontrst[t-NTBASE].tvalue = ty;
165 }
166 case ',':
167 continue;
168
169 case ';':
170 t = gettok();
171 break;
172 default:
173 break;
174 }
175 break;
176 }
177 continue;
178
179 case UNION:
180 /* copy the union declaration to the output */
181 cpyunion();
182 t = gettok();
183 continue;
184
185 case LEFT:
186 case BINARY:
187 case RIGHT:
188 ++i;
189 case TERM:
190 lev = t-TERM; /* nonzero means new prec. and assoc. */
191 ty = 0;
192
193 /* get identifiers so defined */
194
195 t = gettok();
196 if( t == TYPENAME ){ /* there is a type defined */
197 ty = numbval;
198 t = gettok();
199 }
200
201 for(;;) {
202 switch( t ){
203
204 case ',':
205 t = gettok();
206 continue;
207
208 case ';':
209 break;
210
211 case IDENTIFIER:
212 j = chfind(0,tokname);
213 if( lev ){
214 if( ASSOC(toklev[j]) ) error( "redeclaration of precedence of %s", tokname );
215 SETASC(toklev[j],lev);
216 SETPLEV(toklev[j],i);
217 }
218 if( ty ){
219 if( TYPE(toklev[j]) ) error( "redeclaration of type of %s", tokname );
220 SETTYPE(toklev[j],ty);
221 }
222 if( (t=gettok()) == NUMBER ){
223 tokset[j].value = numbval;
224 if( j < ndefout && j>2 ){
225 error( "please define type number of %s earlier",
226 tokset[j].name );
227 }
228 t=gettok();
229 }
230 continue;
231
232 }
233
234 break;
235 }
236
237 continue;
238
239 case LCURLY:
240 defout();
241 cpycode();
242 t = gettok();
243 continue;
244
245 default:
246 error( "syntax error" );
247
248 }
249
250 }
251
252 if( t == ENDFILE ){
253 error( "unexpected EOF before %%" );
254 }
255
256 /* t is MARK */
257
258 defout();
259
260 fprintf( ftable, "#define yyclearin yychar = -1\n" );
261 fprintf( ftable, "#define yyerrok yyerrflag = 0\n" );
262 fprintf( ftable, "extern int yychar;\nextern short yyerrflag;\n" );
263 fprintf( ftable, "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n" );
264 if( !ntypes ) fprintf( ftable, "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n" );
265 fprintf( ftable, "YYSTYPE yylval, yyval;\n" );
266
267 prdptr[0]=mem;
268 /* added production */
269 *mem++ = NTBASE;
270 *mem++ = start; /* if start is 0, we will overwrite with the lhs of the first rule */
271 *mem++ = 1;
272 *mem++ = 0;
273 prdptr[1]=mem;
274
275 while( (t=gettok()) == LCURLY ) cpycode();
276
277 if( t != C_IDENTIFIER ) error( "bad syntax on first rule" );
278
279 if( !start ) prdptr[0][1] = chfind(1,tokname);
280
281 /* read rules */
282
283 while( t!=MARK && t!=ENDFILE ){
284
285 /* process a rule */
286
287 if( t == '|' ){
288 *mem++ = *prdptr[nprod-1];
289 }
290 else if( t == C_IDENTIFIER ){
291 *mem = chfind(1,tokname);
292 if( *mem < NTBASE ) error( "token illegal on LHS of grammar rule" );
293 ++mem;
294 }
295 else error( "illegal rule: missing semicolon or | ?" );
296
297 /* read rule body */
298
299
300 t = gettok();
301 more_rule:
302 while( t == IDENTIFIER ) {
303 *mem = chfind(1,tokname);
304 if( *mem<NTBASE ) levprd[nprod] = toklev[*mem];
305 ++mem;
306 t = gettok();
307 }
308
309
310 if( t == PREC ){
311 if( gettok()!=IDENTIFIER) error( "illegal %%prec syntax" );
312 j = chfind(2,tokname);
313 if( j>=NTBASE)error("nonterminal %s illegal after %%prec", nontrst[j-NTBASE].name);
314 levprd[nprod]=toklev[j];
315 t = gettok();
316 }
317
318 if( t == '=' ){
319 levprd[nprod] |= ACTFLAG;
320 fprintf( faction, "\ncase %d:", nprod );
321 cpyact( mem-prdptr[nprod]-1 );
322 fprintf( faction, " break;" );
323 if( (t=gettok()) == IDENTIFIER ){
324 /* action within rule... */
325
326 sprintf( actname, "$$%d", nprod );
327 j = chfind(1,actname); /* make it a nonterminal */
328
329 /* the current rule will become rule number nprod+1 */
330 /* move the contents down, and make room for the null */
331
332 for( p=mem; p>=prdptr[nprod]; --p ) p[2] = *p;
333 mem += 2;
334
335 /* enter null production for action */
336
337 p = prdptr[nprod];
338
339 *p++ = j;
340 *p++ = -nprod;
341
342 /* update the production information */
343
344 levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
345 levprd[nprod] = ACTFLAG;
346
347 if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
348 prdptr[nprod] = p;
349
350 /* make the action appear in the original rule */
351 *mem++ = j;
352
353 /* get some more of the rule */
354
355 goto more_rule;
356 }
357
358 }
359
360 while( t == ';' ) t = gettok();
361
362 *mem++ = -nprod;
363
364 /* check that default action is reasonable */
365
366 if( ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].tvalue ){
367 /* no explicit action, LHS has value */
368 register tempty;
369 tempty = prdptr[nprod][1];
370 if( tempty < 0 ) error( "must return a value, since LHS has a type" );
371 else if( tempty >= NTBASE ) tempty = nontrst[tempty-NTBASE].tvalue;
372 else tempty = TYPE( toklev[tempty] );
373 if( tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue ){
374 error( "default action causes potential type clash" );
375 }
376 }
377
378 if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
379 prdptr[nprod] = mem;
380 levprd[nprod]=0;
381
382 }
383
384 /* end of all rules */
385
386 finact();
387 if( t == MARK ){
388 fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
389 while( (c=getc(finput)) != EOF ) putc( c, ftable );
390 }
391 fclose( finput );
392 }
393
394finact(){
395 /* finish action routine */
396
397 fclose(faction);
398
399 fprintf( ftable, "# define YYERRCODE %d\n", tokset[2].value );
400
401 }
402
403defin( t, s ) register char *s; {
404/* define s to be a terminal if t=0
405 or a nonterminal if t=1 */
406
407 register val;
408
409 if (t) {
410 if( ++nnonter >= NNONTERM ) error("too many nonterminals, limit %d",NNONTERM);
411 nontrst[nnonter].name = cstash(s);
412 return( NTBASE + nnonter );
413 }
414 /* must be a token */
415 if( ++ntokens >= NTERMS ) error("too many terminals, limit %d",NTERMS );
416 tokset[ntokens].name = cstash(s);
417
418 /* establish value for token */
419
420 if( s[0]==' ' && s[2]=='\0' ) /* single character literal */
421 val = s[1];
422 else if ( s[0]==' ' && s[1]=='\\' ) { /* escape sequence */
423 if( s[3] == '\0' ){ /* single character escape sequence */
424 switch ( s[2] ){
425 /* character which is escaped */
426 case 'n': val = '\n'; break;
427 case 'r': val = '\r'; break;
428 case 'b': val = '\b'; break;
429 case 't': val = '\t'; break;
430 case 'f': val = '\f'; break;
431 case '\'': val = '\''; break;
432 case '"': val = '"'; break;
433 case '\\': val = '\\'; break;
434 default: error( "invalid escape" );
435 }
436 }
437 else if( s[2] <= '7' && s[2]>='0' ){ /* \nnn sequence */
438 if( s[3]<'0' || s[3] > '7' || s[4]<'0' ||
439 s[4]>'7' || s[5] != '\0' ) error("illegal \\nnn construction" );
440 val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
441 if( val == 0 ) error( "'\\000' is illegal" );
442 }
443 }
444 else {
445 val = extval++;
446 }
447 tokset[ntokens].value = val;
448 toklev[ntokens] = 0;
449 return( ntokens );
450 }
451
452defout(){ /* write out the defines (at the end of the declaration section) */
453
454 register int i, c;
455 register char *cp;
456
457 for( i=ndefout; i<=ntokens; ++i ){
458
459 cp = tokset[i].name;
460 if( *cp == ' ' ) ++cp; /* literals */
461
462 for( ; (c= *cp)!='\0'; ++cp ){
463
464 if( islower(c) || isupper(c) || isdigit(c) || c=='_' ); /* VOID */
465 else goto nodef;
466 }
467
468 fprintf( ftable, "# define %s %d\n", tokset[i].name, tokset[i].value );
469 if( fdefine != NULL ) fprintf( fdefine, "# define %s %d\n", tokset[i].name, tokset[i].value );
470
471 nodef: ;
472 }
473
474 ndefout = ntokens+1;
475
476 }
477
478char *
479cstash( s ) register char *s; {
480 char *temp;
481
482 temp = cnamp;
483 do {
484 if( cnamp >= &cnames[cnamsz] ) error("too many characters in id's and literals" );
485 else *cnamp++ = *s;
486 } while ( *s++ );
487 return( temp );
488 }
489
490gettok() {
491 register i, base;
492 static int peekline; /* number of '\n' seen in lookahead */
493 register c, match, reserve;
494
495begin:
496 reserve = 0;
497 lineno += peekline;
498 peekline = 0;
499 c = getc(finput);
500 while( c==' ' || c=='\n' || c=='\t' || c=='\f' ){
501 if( c == '\n' ) ++lineno;
502 c=getc(finput);
503 }
504 if( c == '/' ){ /* skip comment */
505 lineno += skipcom();
506 goto begin;
507 }
508
509 switch(c){
510
511 case EOF:
512 return(ENDFILE);
513 case '{':
514 ungetc( c, finput );
515 return( '=' ); /* action ... */
516 case '<': /* get, and look up, a type name (union member name) */
517 i = 0;
518 while( (c=getc(finput)) != '>' && c>=0 && c!= '\n' ){
519 tokname[i] = c;
520 if( ++i >= NAMESIZE ) --i;
521 }
522 if( c != '>' ) error( "unterminated < ... > clause" );
523 tokname[i] = '\0';
524 for( i=1; i<=ntypes; ++i ){
525 if( !strcmp( typeset[i], tokname ) ){
526 numbval = i;
527 return( TYPENAME );
528 }
529 }
530 typeset[numbval = ++ntypes] = cstash( tokname );
531 return( TYPENAME );
532
533 case '"':
534 case '\'':
535 match = c;
536 tokname[0] = ' ';
537 i = 1;
538 for(;;){
539 c = getc(finput);
540 if( c == '\n' || c == EOF )
541 error("illegal or missing ' or \"" );
542 if( c == '\\' ){
543 c = getc(finput);
544 tokname[i] = '\\';
545 if( ++i >= NAMESIZE ) --i;
546 }
547 else if( c == match ) break;
548 tokname[i] = c;
549 if( ++i >= NAMESIZE ) --i;
550 }
551 break;
552
553 case '%':
554 case '\\':
555
556 switch(c=getc(finput)) {
557
558 case '0': return(TERM);
559 case '<': return(LEFT);
560 case '2': return(BINARY);
561 case '>': return(RIGHT);
562 case '%':
563 case '\\': return(MARK);
564 case '=': return(PREC);
565 case '{': return(LCURLY);
566 default: reserve = 1;
567 }
568
569 default:
570
571 if( isdigit(c) ){ /* number */
572 numbval = c-'0' ;
573 base = (c=='0') ? 8 : 10 ;
574 for( c=getc(finput); isdigit(c) ; c=getc(finput) ){
575 numbval = numbval*base + c - '0';
576 }
577 ungetc( c, finput );
578 return(NUMBER);
579 }
580 else if( islower(c) || isupper(c) || c=='_' || c=='.' || c=='$' ){
581 i = 0;
582 while( islower(c) || isupper(c) || isdigit(c) || c=='_' || c=='.' || c=='$' ){
583 tokname[i] = c;
584 if( reserve && isupper(c) ) tokname[i] += 'a'-'A';
585 if( ++i >= NAMESIZE ) --i;
586 c = getc(finput);
587 }
588 }
589 else return(c);
590
591 ungetc( c, finput );
592 }
593
594 tokname[i] = '\0';
595
596 if( reserve ){ /* find a reserved word */
597 if( !strcmp(tokname,"term")) return( TERM );
598 if( !strcmp(tokname,"token")) return( TERM );
599 if( !strcmp(tokname,"left")) return( LEFT );
600 if( !strcmp(tokname,"nonassoc")) return( BINARY );
601 if( !strcmp(tokname,"binary")) return( BINARY );
602 if( !strcmp(tokname,"right")) return( RIGHT );
603 if( !strcmp(tokname,"prec")) return( PREC );
604 if( !strcmp(tokname,"start")) return( START );
605 if( !strcmp(tokname,"type")) return( TYPEDEF );
606 if( !strcmp(tokname,"union")) return( UNION );
607 error("invalid escape, or illegal reserved word: %s", tokname );
608 }
609
610 /* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
611
612 c = getc(finput);
613 while( c==' ' || c=='\t'|| c=='\n' || c=='\f' || c== '/' ) {
614 if( c == '\n' ) ++peekline;
615 else if( c == '/' ){ /* look for comments */
616 peekline += skipcom();
617 }
618 c = getc(finput);
619 }
620 if( c == ':' ) return( C_IDENTIFIER );
621 ungetc( c, finput );
622 return( IDENTIFIER );
623}
624
625fdtype( t ){ /* determine the type of a symbol */
626 register v;
627 if( t >= NTBASE ) v = nontrst[t-NTBASE].tvalue;
628 else v = TYPE( toklev[t] );
629 if( v <= 0 ) error( "must specify type for %s", (t>=NTBASE)?nontrst[t-NTBASE].name:
630 tokset[t].name );
631 return( v );
632 }
633
634chfind( t, s ) register char *s; {
635 int i;
636
637 if (s[0]==' ')t=0;
638 TLOOP(i){
639 if(!strcmp(s,tokset[i].name)){
640 return( i );
641 }
642 }
643 NTLOOP(i){
644 if(!strcmp(s,nontrst[i].name)) {
645 return( i+NTBASE );
646 }
647 }
648 /* cannot find name */
649 if( t>1 )
650 error( "%s should have been defined earlier", s );
651 return( defin( t, s ) );
652 }
653
654cpyunion(){
655 /* copy the union declaration to the output, and the define file if present */
656
657 int level, c;
658 fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
659 fprintf( ftable, "typedef union " );
660 if( fdefine ) fprintf( fdefine, "\ntypedef union " );
661
662 level = 0;
663 for(;;){
664 if( (c=getc(finput)) < 0 ) error( "EOF encountered while processing %%union" );
665 putc( c, ftable );
666 if( fdefine ) putc( c, fdefine );
667
668 switch( c ){
669
670 case '\n':
671 ++lineno;
672 break;
673
674 case '{':
675 ++level;
676 break;
677
678 case '}':
679 --level;
680 if( level == 0 ) { /* we are finished copying */
681 fprintf( ftable, " YYSTYPE;\n" );
682 if( fdefine ) fprintf( fdefine, " YYSTYPE;\nextern YYSTYPE yylval;\n" );
683 return;
684 }
685 }
686 }
687 }
688
689cpycode(){ /* copies code between \{ and \} */
690
691 int c;
692 c = getc(finput);
693 if( c == '\n' ) {
694 c = getc(finput);
695 lineno++;
696 }
697 fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
698 while( c>=0 ){
699 if( c=='\\' )
700 if( (c=getc(finput)) == '}' ) return;
701 else putc('\\', ftable );
702 if( c=='%' )
703 if( (c=getc(finput)) == '}' ) return;
704 else putc('%', ftable );
705 putc( c , ftable );
706 if( c == '\n' ) ++lineno;
707 c = getc(finput);
708 }
709 error("eof before %%}" );
710 }
711
712skipcom(){ /* skip over comments */
713 register c, i=0; /* i is the number of lines skipped */
714
715 /* skipcom is called after reading a / */
716
717 if( getc(finput) != '*' ) error( "illegal comment" );
718 c = getc(finput);
719 while( c != EOF ){
720 while( c == '*' ){
721 if( (c=getc(finput)) == '/' ) return( i );
722 }
723 if( c == '\n' ) ++i;
724 c = getc(finput);
725 }
726 error( "EOF inside comment" );
727 /* NOTREACHED */
728 }
729
730cpyact(offset){ /* copy C action to the next ; or closing } */
731 int brac, c, match, j, s, tok;
732
733 fprintf( faction, "\n# line %d \"%s\"\n", lineno, infile );
734
735 brac = 0;
736
737loop:
738 c = getc(finput);
739swt:
740 switch( c ){
741
742case ';':
743 if( brac == 0 ){
744 putc( c , faction );
745 return;
746 }
747 goto lcopy;
748
749case '{':
750 brac++;
751 goto lcopy;
752
753case '$':
754 s = 1;
755 tok = -1;
756 c = getc(finput);
757 if( c == '<' ){ /* type description */
758 ungetc( c, finput );
759 if( gettok() != TYPENAME ) error( "bad syntax on $<ident> clause" );
760 tok = numbval;
761 c = getc(finput);
762 }
763 if( c == '$' ){
764 fprintf( faction, "yyval");
765 if( ntypes ){ /* put out the proper tag... */
766 if( tok < 0 ) tok = fdtype( *prdptr[nprod] );
767 fprintf( faction, ".%s", typeset[tok] );
768 }
769 goto loop;
770 }
771 if( c == '-' ){
772 s = -s;
773 c = getc(finput);
774 }
775 if( isdigit(c) ){
776 j=0;
777 while( isdigit(c) ){
778 j= j*10+c-'0';
779 c = getc(finput);
780 }
781
782 j = j*s - offset;
783 if( j > 0 ){
784 error( "Illegal use of $%d", j+offset );
785 }
786
787 fprintf( faction, "yypvt[-%d]", -j );
788 if( ntypes ){ /* put out the proper tag */
789 if( j+offset <= 0 && tok < 0 ) error( "must specify type of $%d", j+offset );
790 if( tok < 0 ) tok = fdtype( prdptr[nprod][j+offset] );
791 fprintf( faction, ".%s", typeset[tok] );
792 }
793 goto swt;
794 }
795 putc( '$' , faction );
796 if( s<0 ) putc('-', faction );
797 goto swt;
798
799case '}':
800 if( --brac ) goto lcopy;
801 putc( c, faction );
802 return;
803
804
805case '/': /* look for comments */
806 putc( c , faction );
807 c = getc(finput);
808 if( c != '*' ) goto swt;
809
810 /* it really is a comment */
811
812 putc( c , faction );
813 c = getc(finput);
814 while( c != EOF ){
815 while( c=='*' ){
816 putc( c , faction );
817 if( (c=getc(finput)) == '/' ) goto lcopy;
818 }
819 putc( c , faction );
820 if( c == '\n' )++lineno;
821 c = getc(finput);
822 }
823 error( "EOF inside comment" );
824
825case '\'': /* character constant */
826 match = '\'';
827 goto string;
828
829case '"': /* character string */
830 match = '"';
831
832 string:
833
834 putc( c , faction );
835 while( c=getc(finput) ){
836
837 if( c=='\\' ){
838 putc( c , faction );
839 c=getc(finput);
840 if( c == '\n' ) ++lineno;
841 }
842 else if( c==match ) goto lcopy;
843 else if( c=='\n' ) error( "newline in string or char. const." );
844 putc( c , faction );
845 }
846 error( "EOF in string or character constant" );
847
848case EOF:
849 error("action does not terminate" );
850
851case '\n': ++lineno;
852 goto lcopy;
853
854 }
855
856lcopy:
857 putc( c , faction );
858 goto loop;
859 }