xref: /freebsd/contrib/flex/src/scan.l (revision f3856e68811a32389fbb8f50d334f7409a6dd2e7)
1 /* scan.l - scanner for flex input -*-C-*- */
2 
3 %{
4 /*  Copyright (c) 1990 The Regents of the University of California. */
5 /*  All rights reserved. */
6 
7 /*  This code is derived from software contributed to Berkeley by */
8 /*  Vern Paxson. */
9 
10 /*  The United States Government has rights in this work pursuant */
11 /*  to contract no. DE-AC03-76SF00098 between the United States */
12 /*  Department of Energy and the University of California. */
13 
14 /*  This file is part of flex. */
15 
16 /*  Redistribution and use in source and binary forms, with or without */
17 /*  modification, are permitted provided that the following conditions */
18 /*  are met: */
19 
20 /*  1. Redistributions of source code must retain the above copyright */
21 /*     notice, this list of conditions and the following disclaimer. */
22 /*  2. Redistributions in binary form must reproduce the above copyright */
23 /*     notice, this list of conditions and the following disclaimer in the */
24 /*     documentation and/or other materials provided with the distribution. */
25 
26 /*  Neither the name of the University nor the names of its contributors */
27 /*  may be used to endorse or promote products derived from this software */
28 /*  without specific prior written permission. */
29 
30 /*  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
31 /*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
32 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
33 /*  PURPOSE. */
34 
35 #include "flexdef.h"
36 #include "parse.h"
37 extern bool tablesverify, tablesext;
38 extern int trlcontxt; /* Set in  parse.y for each rule. */
39 extern const char *escaped_qstart, *escaped_qend;
40 extern int yylval;
41 
42 #define M4QSTART "[""["
43 #define M4QEND "]""]"
44 
45 #define ESCAPED_QSTART "[" M4QEND M4QSTART "[" M4QEND M4QSTART
46 #define ESCAPED_QEND M4QEND "]" M4QSTART M4QEND "]" M4QSTART
47 
48 #define ACTION_ECHO add_action( yytext )
49 #define ACTION_IFDEF(def, should_define) \
50 	{ \
51 	if ( should_define ) \
52 		action_define( def, 1 ); \
53 	}
54 
55 #define ACTION_ECHO_QSTART add_action (ESCAPED_QSTART)
56 #define ACTION_ECHO_QEND   add_action (ESCAPED_QEND)
57 
58 #define ACTION_M4_IFDEF(def, should_define) \
59     do{ \
60         if ( should_define ) \
61             buf_m4_define( &m4defs_buf, def, NULL);\
62         else \
63             buf_m4_undefine( &m4defs_buf, def);\
64     } while(0)
65 
66 #define MARK_END_OF_PROLOG mark_prolog();
67 
68 #define YY_DECL \
69 	int flexscan(void)
70 
71 #define RETURNCHAR \
72 	yylval = (unsigned char) yytext[0]; \
73 	return CHAR;
74 
75 #define RETURNNAME \
76 	if(yyleng < MAXLINE) \
77          { \
78 	strncpy( nmstr, yytext, sizeof(nmstr) ); \
79 	return NAME; \
80 	 } \
81 	else \
82 	 do { \
83 	   synerr(_("Input line too long\n")); \
84 	   FLEX_EXIT(EXIT_FAILURE);  \
85 	 } while (0)
86 
87 #define PUT_BACK_STRING(str, start) \
88 	{ size_t i = strlen( str );	\
89 	  while ( i > start )		\
90 	    unput((str)[--i]);		\
91 	}
92 
93 #define CHECK_REJECT(str) \
94 	if ( all_upper( str ) ) \
95 		reject = true;
96 
97 #define CHECK_YYMORE(str) \
98 	if ( all_lower( str ) ) \
99 		yymore_used = true;
100 
101 #define YY_USER_INIT \
102 	if ( getenv("POSIXLY_CORRECT") ) \
103 		posix_compat = true;
104 
105 #define START_CODEBLOCK(x) do { \
106     /* Emit the needed line directive... */\
107     if (indented_code == false) { \
108         linenum++; \
109         line_directive_out(NULL, 1); \
110     } \
111     add_action(M4QSTART); \
112     yy_push_state(CODEBLOCK); \
113     if ((indented_code = x)) ACTION_ECHO; \
114 } while(0)
115 
116 #define END_CODEBLOCK do { \
117     yy_pop_state();\
118     add_action(M4QEND); \
119     if (!indented_code) line_directive_out(NULL, 0);\
120 } while (0)
121 
122 %}
123 
124 %option caseless nodefault noreject stack noyy_top_state
125 %option nostdinit
126 
127 %x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
128 %x FIRSTCCL CCL ACTION RECOVER COMMENT ACTION_STRING PERCENT_BRACE_ACTION
129 %x OPTION LINEDIR CODEBLOCK_MATCH_BRACE
130 %x GROUP_WITH_PARAMS
131 %x GROUP_MINUS_PARAMS
132 %x EXTENDED_COMMENT
133 %x COMMENT_DISCARD CODE_COMMENT
134 %x SECT3_NOESCAPE
135 %x CHARACTER_CONSTANT
136 
137 WS		[[:blank:]]+
138 OPTWS		[[:blank:]]*
139 NOT_WS		[^[:blank:]\r\n]
140 
141 NL		\r?\n
142 
143 NAME		([[:alpha:]_][[:alnum:]_-]*)
144 NOT_NAME	[^[:alpha:]_*\n]+
145 
146 SCNAME		{NAME}
147 
148 ESCSEQ		(\\([^\n]|[0-7]{1,3}|x[[:xdigit:]]{1,2}))
149 
150 FIRST_CCL_CHAR	([^\\\n]|{ESCSEQ})
151 CCL_CHAR	([^\\\n\]]|{ESCSEQ})
152 CCL_EXPR	("[:"^?[[:alpha:]]+":]")
153 
154 LEXOPT		[aceknopr]
155 
156 M4QSTART    "[""["
157 M4QEND      "]""]"
158 
159 %%
160 	static int bracelevel, didadef, indented_code;
161 	static int doing_rule_action = false;
162 	static int option_sense;
163 
164 	int doing_codeblock = false;
165 	int brace_depth=0, brace_start_line=0;
166 	char nmdef[MAXLINE];
167 
168 
169 <INITIAL>{
170 	^{WS}		START_CODEBLOCK(true);
171 	^"/*"		add_action("/*[""["); yy_push_state( COMMENT );
172 	^#{OPTWS}line{WS}	yy_push_state( LINEDIR );
173 	^"%s"{NAME}?	return SCDECL;
174 	^"%x"{NAME}?	return XSCDECL;
175 	^"%{".*{NL}	START_CODEBLOCK(false);
176     ^"%top"[[:blank:]]*"{"[[:blank:]]*{NL}    {
177                 brace_start_line = linenum;
178                 ++linenum;
179                 buf_linedir( &top_buf, infilename?infilename:"<stdin>", linenum);
180                 brace_depth = 1;
181                 yy_push_state(CODEBLOCK_MATCH_BRACE);
182             }
183 
184     ^"%top".*   synerr( _("malformed '%top' directive") );
185 
186 	{WS}		/* discard */
187 
188 	^"%%".*		{
189 			sectnum = 2;
190 			bracelevel = 0;
191 			mark_defs1();
192 			line_directive_out(NULL, 1);
193 			BEGIN(SECT2PROLOG);
194 			return SECTEND;
195 			}
196 
197 	^"%pointer".*{NL}	yytext_is_array = false; ++linenum;
198 	^"%array".*{NL}		yytext_is_array = true; ++linenum;
199 
200 	^"%option"	BEGIN(OPTION); return TOK_OPTION;
201 
202 	^"%"{LEXOPT}{OPTWS}[[:digit:]]*{OPTWS}{NL}	++linenum; /* ignore */
203 	^"%"{LEXOPT}{WS}.*{NL}	++linenum;	/* ignore */
204 
205 	/* xgettext: no-c-format */
206 	^"%"[^sxaceknopr{}].*	synerr( _( "unrecognized '%' directive" ) );
207 
208 	^{NAME}		{
209 			if(yyleng < MAXLINE)
210         		 {
211 			strncpy( nmstr, yytext, sizeof(nmstr) );
212 			 }
213 			else
214 			 {
215 			   synerr( _("Definition name too long\n"));
216 			   FLEX_EXIT(EXIT_FAILURE);
217 			 }
218 
219 			didadef = false;
220 			BEGIN(PICKUPDEF);
221 			}
222 
223 	{SCNAME}	RETURNNAME;
224 	^{OPTWS}{NL}	++linenum; /* allows blank lines in section 1 */
225 	{OPTWS}{NL}	ACTION_ECHO; ++linenum; /* maybe end of comment line */
226 }
227 
228 
229 <COMMENT,CODE_COMMENT>{ /* */
230         [^\[\]\*\n]*  ACTION_ECHO;
231         .           ACTION_ECHO;
232 
233 	{NL}	    ++linenum; ACTION_ECHO;
234 }
235 <COMMENT>{
236 	"*/"	    add_action("*/]""]"); yy_pop_state();
237 }
238 <CODE_COMMENT>{
239         "*/"        ACTION_ECHO; yy_pop_state();
240 }
241 
242 <COMMENT_DISCARD>{
243         /* This is the same as COMMENT, but is discarded rather than output. */
244 	"*/"		yy_pop_state();
245     "*"         ;
246 	[^*\n]      ;
247 	{NL}	    ++linenum;
248 }
249 
250 <EXTENDED_COMMENT>{
251     ")"         yy_pop_state();
252     [^\n\)]+      ;
253     {NL}        ++linenum;
254 }
255 
256 <LINEDIR>{
257 	\n		yy_pop_state();
258 	[[:digit:]]+	linenum = myctoi( yytext );
259 
260 	\"[^"\n]*\"	{
261 			free(infilename);
262 			infilename = xstrdup(yytext + 1);
263 			infilename[strlen( infilename ) - 1] = '\0';
264 			}
265 	.		/* ignore spurious characters */
266 }
267 <ACTION,CODEBLOCK,ACTION_STRING,PERCENT_BRACE_ACTION,CHARACTER_CONSTANT,COMMENT,CODE_COMMENT>{
268    {M4QSTART}   ACTION_ECHO_QSTART;
269    {M4QEND}     ACTION_ECHO_QEND;
270 }
271 
272 <CODEBLOCK>{
273 	^"%}".*{NL}	++linenum; END_CODEBLOCK;
274 	[^\n%\[\]]*         ACTION_ECHO;
275         .		ACTION_ECHO;
276 	{NL}		{
277 			++linenum;
278 			ACTION_ECHO;
279 			if ( indented_code ) END_CODEBLOCK;
280 			}
281 }
282 
283 <CODEBLOCK_MATCH_BRACE>{
284     "}"     {
285                 if( --brace_depth == 0){
286                     /* TODO: Matched. */
287                     yy_pop_state();
288                 }else
289                     buf_strnappend(&top_buf, yytext, yyleng);
290             }
291 
292     "{"     {
293                 brace_depth++;
294                 buf_strnappend(&top_buf, yytext, yyleng);
295             }
296 
297     {NL}    {
298                 ++linenum;
299                 buf_strnappend(&top_buf, yytext, yyleng);
300             }
301 
302     {M4QSTART}  buf_strnappend(&top_buf, escaped_qstart, (int) strlen(escaped_qstart));
303     {M4QEND}    buf_strnappend(&top_buf, escaped_qend, (int) strlen(escaped_qend));
304     ([^{}\r\n\[\]]+)|[^{}\r\n]  {
305        buf_strnappend(&top_buf, yytext, yyleng);
306     }
307 
308     <<EOF>>     {
309                 linenum = brace_start_line;
310                 synerr(_("Unmatched '{'"));
311                 yyterminate();
312                 }
313 }
314 
315 
316 <PICKUPDEF>{
317 	{WS}		/* separates name and definition */
318 
319 	{NOT_WS}[^\r\n]*	{
320  		        if(yyleng < MAXLINE)
321  		         {
322 			strncpy( nmdef, yytext, sizeof(nmdef) );
323  		         }
324  		        else
325  		         {
326  		           format_synerr( _("Definition value for {%s} too long\n"), nmstr);
327  		           FLEX_EXIT(EXIT_FAILURE);
328 			 }
329 			/* Skip trailing whitespace. */
330 			{
331 			    size_t i = strlen( nmdef );
332 			    while (i > 0 && (nmdef[i-1] == ' ' || nmdef[i-1] == '\t'))
333 			       --i;
334 			    nmdef[i] = '\0';
335 			}
336 
337 			ndinstal( nmstr, nmdef );
338 			didadef = true;
339 			}
340 
341 	{NL}		{
342 			if ( ! didadef )
343 				synerr( _( "incomplete name definition" ) );
344 			BEGIN(INITIAL);
345 			++linenum;
346 			}
347 }
348 
349 
350 <OPTION>{
351 	{NL}		++linenum; BEGIN(INITIAL);
352 	{WS}		option_sense = true;
353 
354 	"="		return '=';
355 
356 	no		option_sense = ! option_sense;
357 
358 	7bit		csize = option_sense ? 128 : 256;
359 	8bit		csize = option_sense ? 256 : 128;
360 
361 	align		long_align = option_sense;
362 	always-interactive	{
363 			ACTION_M4_IFDEF( "M4""_YY_ALWAYS_INTERACTIVE", option_sense );
364             interactive = option_sense;
365 			}
366 	array		yytext_is_array = option_sense;
367 	backup		backing_up_report = option_sense;
368 	batch		interactive = ! option_sense;
369     bison-bridge     bison_bridge_lval = option_sense;
370     bison-locations  { if((bison_bridge_lloc = option_sense))
371                             bison_bridge_lval = true;
372                      }
373 	"c++"		C_plus_plus = option_sense;
374 	caseful|case-sensitive		sf_set_case_ins(!option_sense);
375 	caseless|case-insensitive	sf_set_case_ins(option_sense);
376 	debug		ddebug = option_sense;
377 	default		spprdflt = ! option_sense;
378 	ecs		useecs = option_sense;
379 	fast		{
380 			useecs = usemecs = false;
381 			use_read = fullspd = true;
382 			}
383 	full		{
384 			useecs = usemecs = false;
385 			use_read = fulltbl = true;
386 			}
387 	input		ACTION_IFDEF("YY_NO_INPUT", ! option_sense);
388 	interactive	interactive = option_sense;
389 	lex-compat	lex_compat = option_sense;
390 	posix-compat	posix_compat = option_sense;
391 	line		gen_line_dirs = option_sense;
392 	main		{
393 			ACTION_M4_IFDEF( "M4""_YY_MAIN", option_sense);
394             /* Override yywrap */
395             if( option_sense == true )
396                 do_yywrap = false;
397 			}
398 	meta-ecs	usemecs = option_sense;
399 	never-interactive	{
400 			ACTION_M4_IFDEF( "M4""_YY_NEVER_INTERACTIVE", option_sense );
401             interactive = !option_sense;
402 			}
403 	perf-report	performance_report += option_sense ? 1 : -1;
404 	pointer		yytext_is_array = ! option_sense;
405 	read		use_read = option_sense;
406     reentrant   reentrant = option_sense;
407 	reject		reject_really_used = option_sense;
408 	stack		ACTION_M4_IFDEF( "M4""_YY_STACK_USED", option_sense );
409 	stdinit		do_stdinit = option_sense;
410 	stdout		use_stdout = option_sense;
411     unistd      ACTION_IFDEF("YY_NO_UNISTD_H", ! option_sense);
412 	unput		ACTION_M4_IFDEF("M4""_YY_NO_UNPUT", ! option_sense);
413 	verbose		printstats = option_sense;
414 	warn		nowarn = ! option_sense;
415 	yylineno	do_yylineno = option_sense; ACTION_M4_IFDEF("M4""_YY_USE_LINENO", option_sense);
416 	yymore		yymore_really_used = option_sense;
417 	yywrap      do_yywrap = option_sense;
418 
419 	yy_push_state	ACTION_M4_IFDEF("M4""_YY_NO_PUSH_STATE", ! option_sense);
420 	yy_pop_state	ACTION_M4_IFDEF("M4""_YY_NO_POP_STATE", ! option_sense);
421 	yy_top_state	ACTION_M4_IFDEF("M4""_YY_NO_TOP_STATE", ! option_sense);
422 
423 	yy_scan_buffer	ACTION_M4_IFDEF("M4""_YY_NO_SCAN_BUFFER", ! option_sense);
424 	yy_scan_bytes	ACTION_M4_IFDEF("M4""_YY_NO_SCAN_BYTES", ! option_sense);
425 	yy_scan_string	ACTION_M4_IFDEF("M4""_YY_NO_SCAN_STRING", ! option_sense);
426 
427     yyalloc         ACTION_M4_IFDEF("M4""_YY_NO_FLEX_ALLOC", ! option_sense);
428     yyrealloc       ACTION_M4_IFDEF("M4""_YY_NO_FLEX_REALLOC", ! option_sense);
429     yyfree          ACTION_M4_IFDEF("M4""_YY_NO_FLEX_FREE", ! option_sense);
430 
431     yyget_debug     ACTION_M4_IFDEF("M4""_YY_NO_GET_DEBUG", ! option_sense);
432     yyset_debug     ACTION_M4_IFDEF("M4""_YY_NO_SET_DEBUG", ! option_sense);
433     yyget_extra     ACTION_M4_IFDEF("M4""_YY_NO_GET_EXTRA", ! option_sense);
434     yyset_extra     ACTION_M4_IFDEF("M4""_YY_NO_SET_EXTRA", ! option_sense);
435     yyget_leng      ACTION_M4_IFDEF("M4""_YY_NO_GET_LENG", ! option_sense);
436     yyget_text      ACTION_M4_IFDEF("M4""_YY_NO_GET_TEXT", ! option_sense);
437     yyget_lineno    ACTION_M4_IFDEF("M4""_YY_NO_GET_LINENO", ! option_sense);
438     yyset_lineno    ACTION_M4_IFDEF("M4""_YY_NO_SET_LINENO", ! option_sense);
439     yyget_in        ACTION_M4_IFDEF("M4""_YY_NO_GET_IN", ! option_sense);
440     yyset_in        ACTION_M4_IFDEF("M4""_YY_NO_SET_IN", ! option_sense);
441     yyget_out       ACTION_M4_IFDEF("M4""_YY_NO_GET_OUT", ! option_sense);
442     yyset_out       ACTION_M4_IFDEF("M4""_YY_NO_SET_OUT", ! option_sense);
443     yyget_lval      ACTION_M4_IFDEF("M4""_YY_NO_GET_LVAL", ! option_sense);
444     yyset_lval      ACTION_M4_IFDEF("M4""_YY_NO_SET_LVAL", ! option_sense);
445     yyget_lloc      ACTION_M4_IFDEF("M4""_YY_NO_GET_LLOC", ! option_sense);
446     yyset_lloc      ACTION_M4_IFDEF("M4""_YY_NO_SET_LLOC", ! option_sense);
447 
448 	extra-type	return TOK_EXTRA_TYPE;
449 	outfile		return TOK_OUTFILE;
450 	prefix		return TOK_PREFIX;
451 	yyclass		return TOK_YYCLASS;
452 	header(-file)?      return TOK_HEADER_FILE;
453 	tables-file         return TOK_TABLES_FILE;
454 	tables-verify   {
455                     tablesverify = option_sense;
456                     if(!tablesext && option_sense)
457                         tablesext = true;
458                     }
459 
460 
461 	\"[^"\n]*\"	{
462 			if(yyleng-1 < MAXLINE)
463         		 {
464 			strncpy( nmstr, yytext + 1, sizeof(nmstr) );
465 			 }
466 			else
467 			 {
468 			   synerr( _("Option line too long\n"));
469 			   FLEX_EXIT(EXIT_FAILURE);
470 			 }
471 			nmstr[strlen( nmstr ) - 1] = '\0';
472 			return NAME;
473 			}
474 
475 	(([a-mo-z]|n[a-np-z])[[:alpha:]\-+]*)|.	{
476 			format_synerr( _( "unrecognized %%option: %s" ),
477 				yytext );
478 			BEGIN(RECOVER);
479 			}
480 }
481 
482 <RECOVER>.*{NL}		++linenum; BEGIN(INITIAL);
483 
484 
485 <SECT2PROLOG>{
486 	^"%{".*	++bracelevel; yyless( 2 );	/* eat only %{ */
487 	^"%}".*	--bracelevel; yyless( 2 );	/* eat only %} */
488 
489 	^{WS} START_CODEBLOCK(true); /* indented code in prolog */
490 
491 	^{NOT_WS}.*	{
492         /* non-indented code */
493 		if ( bracelevel <= 0 ) {
494             /* not in %{ ... %} */
495             yyless( 0 );	/* put it all back */
496             yy_set_bol( 1 );
497             mark_prolog();
498             BEGIN(SECT2);
499         } else {
500             START_CODEBLOCK(true);
501         }
502     }
503 
504 	.		ACTION_ECHO;
505 	{NL}	++linenum; ACTION_ECHO;
506 
507 	<<EOF>>		{
508 			mark_prolog();
509 			sectnum = 0;
510 			yyterminate(); /* to stop the parser */
511 			}
512 }
513 
514 <SECT2>{
515 	^{OPTWS}{NL}	++linenum; /* allow blank lines in section 2 */
516 
517 	^{OPTWS}"%{"	{
518 			indented_code = false;
519 			doing_codeblock = true;
520 			bracelevel = 1;
521 			BEGIN(PERCENT_BRACE_ACTION);
522 			}
523 
524 	^{OPTWS}"<"	    {
525                         /* Allow "<" to appear in (?x) patterns. */
526                         if (!sf_skip_ws())
527                             BEGIN(SC);
528                         return '<';
529                     }
530 	^{OPTWS}"^"	return '^';
531 	\"		BEGIN(QUOTE); return '"';
532 	"{"/[[:digit:]]	{
533 			BEGIN(NUM);
534 			if ( lex_compat || posix_compat )
535 				return BEGIN_REPEAT_POSIX;
536 			else
537 				return BEGIN_REPEAT_FLEX;
538 			}
539 	"$"/([[:blank:]]|{NL})	return '$';
540 
541 	{WS}"%{"		{
542 			bracelevel = 1;
543 			BEGIN(PERCENT_BRACE_ACTION);
544 
545 			if ( in_rule )
546 				{
547 				doing_rule_action = true;
548 				in_rule = false;
549 				return '\n';
550 				}
551 			}
552 	{WS}"|".*{NL}	{
553                         if (sf_skip_ws()){
554                             /* We're in the middle of a (?x: ) pattern. */
555                             /* Push back everything starting at the "|" */
556                             int amt = (int) (strchr (yytext, '|') - yytext);
557                             yyless(amt);
558                         }
559                         else {
560                             add_action("]""]");
561                             continued_action = true;
562                             ++linenum;
563                             return '\n';
564                         }
565                     }
566 
567 	^{WS}"/*"	{
568 
569                 if (sf_skip_ws()){
570                     /* We're in the middle of a (?x: ) pattern. */
571                     yy_push_state(COMMENT_DISCARD);
572                 }
573                 else{
574                     yyless( yyleng - 2 );	/* put back '/', '*' */
575                     bracelevel = 0;
576                     continued_action = false;
577                     BEGIN(ACTION);
578                 }
579 			}
580 
581 	^{WS}		/* allow indented rules */ ;
582 
583 	{WS}		{
584             if (sf_skip_ws()){
585                 /* We're in the middle of a (?x: ) pattern. */
586             }
587             else{
588                 /* This rule is separate from the one below because
589                  * otherwise we get variable trailing context, so
590                  * we can't build the scanner using -{f,F}.
591                  */
592                 bracelevel = 0;
593                 continued_action = false;
594                 BEGIN(ACTION);
595 
596                 if ( in_rule )
597                     {
598                     doing_rule_action = true;
599                     in_rule = false;
600                     return '\n';
601                     }
602             }
603 			}
604 
605 	{OPTWS}{NL}	{
606             if (sf_skip_ws()){
607                 /* We're in the middle of a (?x: ) pattern. */
608                 ++linenum;
609             }
610             else{
611                 bracelevel = 0;
612                 continued_action = false;
613                 BEGIN(ACTION);
614                 unput( '\n' );	/* so <ACTION> sees it */
615 
616                 if ( in_rule )
617                     {
618                     doing_rule_action = true;
619                     in_rule = false;
620                     return '\n';
621                     }
622             }
623 			}
624 
625 	^{OPTWS}"<<EOF>>"	|
626 	"<<EOF>>"	return EOF_OP;
627 
628 	^"%%".*		{
629 			sectnum = 3;
630 			BEGIN(no_section3_escape ? SECT3_NOESCAPE : SECT3);
631 			outn("/* Begin user sect3 */");
632 			yyterminate(); /* to stop the parser */
633 
634 			}
635 
636 	"["({FIRST_CCL_CHAR}|{CCL_EXPR})({CCL_CHAR}|{CCL_EXPR})*	{
637 			int cclval;
638 
639 			if(yyleng < MAXLINE)
640         		 {
641 			strncpy( nmstr, yytext, sizeof(nmstr) );
642 			 }
643 			else
644 			 {
645 			   synerr( _("Input line too long\n"));
646 			   FLEX_EXIT(EXIT_FAILURE);
647 			 }
648 
649 			/* Check to see if we've already encountered this
650 			 * ccl.
651 			 */
652 			if (0 /* <--- This "0" effectively disables the reuse of a
653                    * character class (purely based on its source text).
654                    * The reason it was disabled is so yacc/bison can parse
655                    * ccl operations, such as ccl difference and union.
656                    */
657                 &&  (cclval = ccllookup( nmstr )) != 0 )
658 				{
659 				if ( input() != ']' )
660 					synerr( _( "bad character class" ) );
661 
662 				yylval = cclval;
663 				++cclreuse;
664 				return PREVCCL;
665 				}
666 			else
667 				{
668 				/* We fudge a bit.  We know that this ccl will
669 				 * soon be numbered as lastccl + 1 by cclinit.
670 				 */
671 				cclinstal( nmstr, lastccl + 1 );
672 
673 				/* Push back everything but the leading bracket
674 				 * so the ccl can be rescanned.
675 				 */
676 				yyless( 1 );
677 
678 				BEGIN(FIRSTCCL);
679 				return '[';
680 				}
681 			}
682     "{-}"       return CCL_OP_DIFF;
683     "{+}"       return CCL_OP_UNION;
684 
685 
686     /* Check for :space: at the end of the rule so we don't
687      * wrap the expanded regex in '(' ')' -- breaking trailing
688      * context.
689      */
690 	"{"{NAME}"}"[[:space:]]?	 {
691 			char *nmdefptr;
692             int end_is_ws, end_ch;
693 
694             end_ch = yytext[yyleng-1];
695             end_is_ws = end_ch != '}' ? 1 : 0;
696 
697  			if(yyleng-1 < MAXLINE)
698          		 {
699 			strncpy( nmstr, yytext + 1, sizeof(nmstr) );
700  			 }
701  			else
702  			 {
703  			   synerr( _("Input line too long\n"));
704  			   FLEX_EXIT(EXIT_FAILURE);
705  			 }
706 nmstr[yyleng - 2 - end_is_ws] = '\0';  /* chop trailing brace */
707 
708 			if ( (nmdefptr = ndlookup( nmstr )) == 0 )
709 				format_synerr(
710 					_( "undefined definition {%s}" ),
711 						nmstr );
712 
713 			else
714 				{ /* push back name surrounded by ()'s */
715 				size_t len = strlen( nmdefptr );
716                 if (end_is_ws)
717                     unput(end_ch);
718 
719 				if ( lex_compat || nmdefptr[0] == '^' ||
720 				     (len > 0 && nmdefptr[len - 1] == '$')
721                      || (end_is_ws && trlcontxt && !sf_skip_ws()))
722 					{ /* don't use ()'s after all */
723 					PUT_BACK_STRING(nmdefptr, 0);
724 
725 					if ( nmdefptr[0] == '^' )
726 						BEGIN(CARETISBOL);
727 					}
728 
729 				else
730 					{
731 					unput(')');
732 					PUT_BACK_STRING(nmdefptr, 0);
733 					unput('(');
734 					}
735 				}
736 			}
737 
738     "/*"        {
739                     if (sf_skip_ws())
740                         yy_push_state(COMMENT_DISCARD);
741                     else{
742                         /* Push back the "*" and return "/" as usual. */
743                         yyless(1);
744                         return '/';
745                     }
746                 }
747 
748     "(?#"       {
749                     if (lex_compat || posix_compat){
750                         /* Push back the "?#" and treat it like a normal parens. */
751                         yyless(1);
752                         sf_push();
753                         return '(';
754                     }
755                     else
756                         yy_push_state(EXTENDED_COMMENT);
757                 }
758     "(?"        {
759                     sf_push();
760                     if (lex_compat || posix_compat)
761                         /* Push back the "?" and treat it like a normal parens. */
762                         yyless(1);
763                     else
764                         BEGIN(GROUP_WITH_PARAMS);
765                     return '(';
766                 }
767     "("         sf_push(); return '(';
768     ")"         {
769                     if (_sf_top_ix > 0) {
770                         sf_pop();
771                         return ')';
772                     } else
773                         synerr(_("unbalanced parenthesis"));
774                 }
775 
776 	[/|*+?.(){}]	return (unsigned char) yytext[0];
777 	.		RETURNCHAR;
778 }
779 
780 
781 <SC>{
782 	{OPTWS}{NL}{OPTWS}	++linenum;	/* Allow blank lines & continuations */
783 	[,*]		return (unsigned char) yytext[0];
784 	">"		BEGIN(SECT2); return '>';
785 	">"/^		BEGIN(CARETISBOL); return '>';
786 	{SCNAME}	RETURNNAME;
787 	.		{
788 			format_synerr( _( "bad <start condition>: %s" ),
789 				yytext );
790 			}
791 }
792 
793 <CARETISBOL>"^"		BEGIN(SECT2); return '^';
794 
795 
796 <QUOTE>{
797 	[^"\n]		RETURNCHAR;
798 	\"		BEGIN(SECT2); return '"';
799 
800 	{NL}		{
801 			synerr( _( "missing quote" ) );
802 			BEGIN(SECT2);
803 			++linenum;
804 			return '"';
805 			}
806 }
807 
808 <GROUP_WITH_PARAMS>{
809     ":"     BEGIN(SECT2);
810     "-"     BEGIN(GROUP_MINUS_PARAMS);
811     i       sf_set_case_ins(1);
812     s       sf_set_dot_all(1);
813     x       sf_set_skip_ws(1);
814 }
815 <GROUP_MINUS_PARAMS>{
816     ":"     BEGIN(SECT2);
817     i       sf_set_case_ins(0);
818     s       sf_set_dot_all(0);
819     x       sf_set_skip_ws(0);
820 }
821 
822 <FIRSTCCL>{
823 	"^"/[^-\]\n]	BEGIN(CCL); return '^';
824 	"^"/("-"|"]")	return '^';
825 	.		BEGIN(CCL); RETURNCHAR;
826 }
827 
828 <CCL>{
829 	-/[^\]\n]	return '-';
830 	[^\]\n]		RETURNCHAR;
831 	"]"		BEGIN(SECT2); return ']';
832 	.|{NL}		{
833 			synerr( _( "bad character class" ) );
834 			BEGIN(SECT2);
835 			return ']';
836 			}
837 }
838 
839 <FIRSTCCL,CCL>{
840 	"[:alnum:]"	BEGIN(CCL); return CCE_ALNUM;
841 	"[:alpha:]"	BEGIN(CCL); return CCE_ALPHA;
842 	"[:blank:]"	BEGIN(CCL); return CCE_BLANK;
843 	"[:cntrl:]"	BEGIN(CCL); return CCE_CNTRL;
844 	"[:digit:]"	BEGIN(CCL); return CCE_DIGIT;
845 	"[:graph:]"	BEGIN(CCL); return CCE_GRAPH;
846 	"[:lower:]"	BEGIN(CCL); return CCE_LOWER;
847 	"[:print:]"	BEGIN(CCL); return CCE_PRINT;
848 	"[:punct:]"	BEGIN(CCL); return CCE_PUNCT;
849 	"[:space:]"	BEGIN(CCL); return CCE_SPACE;
850 	"[:upper:]"	BEGIN(CCL); return CCE_UPPER;
851 	"[:xdigit:]"	BEGIN(CCL); return CCE_XDIGIT;
852 
853 	"[:^alnum:]"	BEGIN(CCL); return CCE_NEG_ALNUM;
854 	"[:^alpha:]"	BEGIN(CCL); return CCE_NEG_ALPHA;
855 	"[:^blank:]"	BEGIN(CCL); return CCE_NEG_BLANK;
856 	"[:^cntrl:]"	BEGIN(CCL); return CCE_NEG_CNTRL;
857 	"[:^digit:]"	BEGIN(CCL); return CCE_NEG_DIGIT;
858 	"[:^graph:]"	BEGIN(CCL); return CCE_NEG_GRAPH;
859 	"[:^lower:]"	BEGIN(CCL); return CCE_NEG_LOWER;
860 	"[:^print:]"	BEGIN(CCL); return CCE_NEG_PRINT;
861 	"[:^punct:]"	BEGIN(CCL); return CCE_NEG_PUNCT;
862 	"[:^space:]"	BEGIN(CCL); return CCE_NEG_SPACE;
863 	"[:^upper:]"	BEGIN(CCL); return CCE_NEG_UPPER;
864 	"[:^xdigit:]"	BEGIN(CCL); return CCE_NEG_XDIGIT;
865 	{CCL_EXPR}	{
866 			format_synerr(
867 				_( "bad character class expression: %s" ),
868 					yytext );
869 			BEGIN(CCL); return CCE_ALNUM;
870 			}
871 }
872 
873 <NUM>{
874 	[[:digit:]]+	{
875 			yylval = myctoi( yytext );
876 			return NUMBER;
877 			}
878 
879 	","		return ',';
880 	"}"		{
881 			BEGIN(SECT2);
882 			if ( lex_compat || posix_compat )
883 				return END_REPEAT_POSIX;
884 			else
885 				return END_REPEAT_FLEX;
886 			}
887 
888 	.		{
889 			synerr( _( "bad character inside {}'s" ) );
890 			BEGIN(SECT2);
891 			return '}';
892 			}
893 
894 	{NL}		{
895 			synerr( _( "missing }" ) );
896 			BEGIN(SECT2);
897 			++linenum;
898 			return '}';
899 			}
900 }
901 
902 
903 <PERCENT_BRACE_ACTION>{
904 	{OPTWS}"%}".*		bracelevel = 0;
905 
906 	<ACTION>"/*"		ACTION_ECHO; yy_push_state( CODE_COMMENT );
907 
908 	<CODEBLOCK,ACTION>{
909 		"reject" {
910             ACTION_ECHO;
911             CHECK_REJECT(yytext);
912         }
913 		"yymore" {
914             ACTION_ECHO;
915             CHECK_YYMORE(yytext);
916         }
917 	}
918 
919     .       ACTION_ECHO;
920 	{NL}	{
921 		++linenum;
922 		ACTION_ECHO;
923 		if (bracelevel <= 0 || (doing_codeblock && indented_code)) {
924             if ( doing_rule_action )
925                 add_action( "\tYY_BREAK]""]\n" );
926 
927             doing_rule_action = doing_codeblock = false;
928             BEGIN(SECT2);
929         }
930     }
931 }
932 
933 
934 	/* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
935 <ACTION>{
936 	"{"		ACTION_ECHO; ++bracelevel;
937 	"}"		ACTION_ECHO; --bracelevel;
938 	[^[:alpha:]_{}\"'/\n\[\]]+	ACTION_ECHO;
939         {NAME}		ACTION_ECHO;
940         "'"([^\'\\\n]|\\.)"'" ACTION_ECHO; /* character constant */
941         "'"             ACTION_ECHO; BEGIN(CHARACTER_CONSTANT);
942 	\"		ACTION_ECHO; BEGIN(ACTION_STRING);
943 	{NL} {
944                 ++linenum;
945                 ACTION_ECHO;
946                 if (bracelevel <= 0) {
947                    if ( doing_rule_action )
948                       add_action( "\tYY_BREAK]""]\n" );
949 
950                    doing_rule_action = false;
951                    BEGIN(SECT2);
952                 }
953              }
954         .      ACTION_ECHO;
955 }
956 
957 <ACTION_STRING>{
958 	[^\[\]\"\\\n]+	ACTION_ECHO;
959 	\"		ACTION_ECHO; BEGIN(ACTION);
960 }
961 <CHARACTER_CONSTANT>{
962 	[^\[\]\'\\\n]+  ACTION_ECHO;
963         \'              ACTION_ECHO; BEGIN(ACTION);
964 }
965 <ACTION_STRING,CHARACTER_CONSTANT>{
966         (\\\n)*         ACTION_ECHO;
967 	\\(\\\n)*.	ACTION_ECHO;
968 	{NL}	++linenum; ACTION_ECHO; if (bracelevel <= 0) { BEGIN(SECT2); } else { BEGIN(ACTION); }
969         .	ACTION_ECHO;
970 }
971 
972 <COMMENT,CODE_COMMENT,COMMENT_DISCARD,ACTION,ACTION_STRING,CHARACTER_CONSTANT><<EOF>>	{
973 			synerr( _( "EOF encountered inside an action" ) );
974 			yyterminate();
975 			}
976 
977 <EXTENDED_COMMENT,GROUP_WITH_PARAMS,GROUP_MINUS_PARAMS><<EOF>>	{
978 			synerr( _( "EOF encountered inside pattern" ) );
979 			yyterminate();
980 			}
981 
982 <SECT2,QUOTE,FIRSTCCL,CCL>{ESCSEQ}	{
983 			yylval = myesc( (unsigned char *) yytext );
984 
985 			if ( YY_START == FIRSTCCL )
986 				BEGIN(CCL);
987 
988 			return CHAR;
989 			}
990 
991 <SECT3>{
992     {M4QSTART}   fputs(escaped_qstart, yyout);
993     {M4QEND}     fputs(escaped_qend, yyout);
994     [^\[\]]*     ECHO;
995     [][]         ECHO;
996     <<EOF>>      {
997         sectnum = 0;
998         yyterminate();
999     }
1000 }
1001 <SECT3_NOESCAPE>{
1002     {M4QSTART}  fprintf(yyout, "[""[%s]""]", escaped_qstart);
1003     {M4QEND}    fprintf(yyout, "[""[%s]""]", escaped_qend);
1004     [^][]*      ECHO;
1005     [][]        ECHO;
1006     <<EOF>>		{
1007        sectnum = 0;
1008        yyterminate();
1009     }
1010 }
1011 <*>.|\n			format_synerr( _( "bad character: %s" ), yytext );
1012 
1013 %%
1014 
1015 
1016 int yywrap(void)
1017 	{
1018 	if ( --num_input_files > 0 )
1019 		{
1020 		set_input_file( *++input_files );
1021 		return 0;
1022 		}
1023 
1024 	else
1025 		return 1;
1026 	}
1027 
1028 
1029 /* set_input_file - open the given file (if NULL, stdin) for scanning */
1030 
1031 void set_input_file( char *file )
1032 	{
1033 	if ( file && strcmp( file, "-" ) )
1034 		{
1035 		infilename = xstrdup(file);
1036 		yyin = fopen( infilename, "r" );
1037 
1038 		if ( yyin == NULL )
1039 			lerr( _( "can't open %s" ), file );
1040 		}
1041 
1042 	else
1043 		{
1044 		yyin = stdin;
1045 		infilename = xstrdup("<stdin>");
1046 		}
1047 
1048 	linenum = 1;
1049 	}
1050