/* $NetBSD: scan.l,v 1.6 2018/12/23 16:27:17 christos Exp $ */
/* scan.l - scanner for flex input -*-C-*- */
%{
/* Copyright (c) 1990 The Regents of the University of California. */
/* All rights reserved. */
/* This code is derived from software contributed to Berkeley by */
/* Vern Paxson. */
/* The United States Government has rights in this work pursuant */
/* to contract no. DE-AC03-76SF00098 between the United States */
/* Department of Energy and the University of California. */
/* This file is part of flex. */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions */
/* are met: */
/* 1. Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* 2. Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the */
/* documentation and/or other materials provided with the distribution. */
/* Neither the name of the University nor the names of its contributors */
/* may be used to endorse or promote products derived from this software */
/* without specific prior written permission. */
/* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */
/* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
/* PURPOSE. */
#include "flexdef.h"
__RCSID("$NetBSD: scan.l,v 1.6 2018/12/23 16:27:17 christos Exp $");
#include "parse.h"
extern bool tablesverify, tablesext;
extern int trlcontxt; /* Set in parse.y for each rule. */
extern const char *escaped_qstart, *escaped_qend;
extern int yylval; /* XXX: for bootstrap */
#define M4QSTART "[""["
#define M4QEND "]""]"
#define ESCAPED_QSTART "[" M4QEND M4QSTART "[" M4QEND M4QSTART
#define ESCAPED_QEND M4QEND "]" M4QSTART M4QEND "]" M4QSTART
#define ACTION_ECHO add_action( yytext )
#define ACTION_IFDEF(def, should_define) \
{ \
if ( should_define ) \
action_define( def, 1 ); \
}
#define ACTION_ECHO_QSTART add_action (ESCAPED_QSTART)
#define ACTION_ECHO_QEND add_action (ESCAPED_QEND)
#define ACTION_M4_IFDEF(def, should_define) \
do{ \
if ( should_define ) \
buf_m4_define( &m4defs_buf, def, NULL);\
else \
buf_m4_undefine( &m4defs_buf, def);\
} while(0)
#define MARK_END_OF_PROLOG mark_prolog();
#define YY_DECL \
int flexscan(void)
#define RETURNCHAR \
yylval = (unsigned char) yytext[0]; \
return CHAR;
#define RETURNNAME \
if(yyleng < MAXLINE) \
{ \
strlcpy( nmstr, yytext, sizeof(nmstr) ); \
return NAME; \
} \
else \
do { \
synerr(_("Input line too long\n")); \
FLEX_EXIT(EXIT_FAILURE); \
} while (0)
#define PUT_BACK_STRING(str, start) \
{ size_t i = strlen( str ); \
while ( i > start ) \
unput((str)[--i]); \
}
#define CHECK_REJECT(str) \
if ( all_upper( str ) ) \
reject = true;
#define CHECK_YYMORE(str) \
if ( all_lower( str ) ) \
yymore_used = true;
#define YY_USER_INIT \
if ( getenv("POSIXLY_CORRECT") ) \
posix_compat = true;
#define START_CODEBLOCK(x) do { \
/* Emit the needed line directive... */\
if (indented_code == false) { \
linenum++; \
line_directive_out(NULL, 1); \
} \
add_action(M4QSTART); \
yy_push_state(CODEBLOCK); \
if ((indented_code = x)) ACTION_ECHO; \
} while(0)
#define END_CODEBLOCK do { \
yy_pop_state();\
add_action(M4QEND); \
if (!indented_code) line_directive_out(NULL, 0);\
} while (0)
%}
%option caseless nodefault noreject stack noyy_top_state
%option nostdinit
%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
%x FIRSTCCL CCL ACTION RECOVER COMMENT ACTION_STRING PERCENT_BRACE_ACTION
%x OPTION LINEDIR CODEBLOCK_MATCH_BRACE
%x GROUP_WITH_PARAMS
%x GROUP_MINUS_PARAMS
%x EXTENDED_COMMENT
%x COMMENT_DISCARD CODE_COMMENT
%x SECT3_NOESCAPE
%x CHARACTER_CONSTANT
WS [[:blank:]]+
OPTWS [[:blank:]]*
NOT_WS [^[:blank:]\r\n]
NL \r?\n
NAME ([[:alpha:]_][[:alnum:]_-]*)
NOT_NAME [^[:alpha:]_*\n]+
SCNAME {NAME}
ESCSEQ (\\([^\n]|[0-7]{1,3}|x[[:xdigit:]]{1,2}))
FIRST_CCL_CHAR ([^\\\n]|{ESCSEQ})
CCL_CHAR ([^\\\n\]]|{ESCSEQ})
CCL_EXPR ("[:"^?[[:alpha:]]+":]")
LEXOPT [aceknopr]
M4QSTART "[""["
M4QEND "]""]"
%%
static int bracelevel, didadef, indented_code;
static int doing_rule_action = false;
static int option_sense;
int doing_codeblock = false;
int brace_depth=0, brace_start_line=0;
char nmdef[MAXLINE];
<INITIAL>{
^{WS} START_CODEBLOCK(true);
^"/*" add_action("/*[""["); yy_push_state( COMMENT );
^#{OPTWS}line{WS} yy_push_state( LINEDIR );
^"%s"{NAME}? return SCDECL;
^"%x"{NAME}? return XSCDECL;
^"%{".*{NL} START_CODEBLOCK(false);
^"%top"[[:blank:]]*"{"[[:blank:]]*{NL} {
brace_start_line = linenum;
++linenum;
buf_linedir( &top_buf, infilename?infilename:"<stdin>", linenum);
brace_depth = 1;
yy_push_state(CODEBLOCK_MATCH_BRACE);
}
^"%top".* synerr( _("malformed '%top' directive") );
{WS} /* discard */
^"%%".* {
sectnum = 2;
bracelevel = 0;
mark_defs1();
line_directive_out(NULL, 1);
BEGIN(SECT2PROLOG);
return SECTEND;
}
^"%pointer".*{NL} yytext_is_array = false; ++linenum;
^"%array".*{NL} yytext_is_array = true; ++linenum;
^"%option" BEGIN(OPTION); return TOK_OPTION;
^"%"{LEXOPT}{OPTWS}[[:digit:]]*{OPTWS}{NL} ++linenum; /* ignore */
^"%"{LEXOPT}{WS}.*{NL} ++linenum; /* ignore */
/* xgettext: no-c-format */
^"%"[^sxaceknopr{}].* synerr( _( "unrecognized '%' directive" ) );
^{NAME} {
if(yyleng < MAXLINE)
{
strlcpy( nmstr, yytext, sizeof(nmstr) );
}
else
{
synerr( _("Definition name too long\n"));
FLEX_EXIT(EXIT_FAILURE);
}
didadef = false;
BEGIN(PICKUPDEF);
}
{SCNAME} RETURNNAME;
^{OPTWS}{NL} ++linenum; /* allows blank lines in section 1 */
{OPTWS}{NL} ACTION_ECHO; ++linenum; /* maybe end of comment line */
}
<COMMENT,CODE_COMMENT>{ /* */
[^\[\]\*\n]* ACTION_ECHO;
. ACTION_ECHO;
{NL} ++linenum; ACTION_ECHO;
}
<COMMENT>{
"*/" add_action("*/]""]"); yy_pop_state();
}
<CODE_COMMENT>{
"*/" ACTION_ECHO; yy_pop_state();
}
<COMMENT_DISCARD>{
/* This is the same as COMMENT, but is discarded rather than output. */
"*/" yy_pop_state();
"*" ;
[^*\n] ;
{NL} ++linenum;
}
<EXTENDED_COMMENT>{
")" yy_pop_state();
[^\n\)]+ ;
{NL} ++linenum;
}
<LINEDIR>{
\n yy_pop_state();
[[:digit:]]+ linenum = myctoi( yytext );
\"[^"\n]*\" {
free(infilename);
infilename = xstrdup(yytext + 1);
infilename[strlen( infilename ) - 1] = '\0';
}
. /* ignore spurious characters */
}
<ACTION,CODEBLOCK,ACTION_STRING,PERCENT_BRACE_ACTION,CHARACTER_CONSTANT,COMMENT,CODE_COMMENT>{
{M4QSTART} ACTION_ECHO_QSTART;
{M4QEND} ACTION_ECHO_QEND;
}
<CODEBLOCK>{
^"%}".*{NL} ++linenum; END_CODEBLOCK;
[^\n%\[\]]* ACTION_ECHO;
. ACTION_ECHO;
{NL} {
++linenum;
ACTION_ECHO;
if ( indented_code ) END_CODEBLOCK;
}
}
<CODEBLOCK_MATCH_BRACE>{
"}" {
if( --brace_depth == 0){
/* TODO: Matched. */
yy_pop_state();
}else
buf_strnappend(&top_buf, yytext, yyleng);
}
"{" {
brace_depth++;
buf_strnappend(&top_buf, yytext, yyleng);
}
{NL} {
++linenum;
buf_strnappend(&top_buf, yytext, yyleng);
}
{M4QSTART} buf_strnappend(&top_buf, escaped_qstart, (int) strlen(escaped_qstart));
{M4QEND} buf_strnappend(&top_buf, escaped_qend, (int) strlen(escaped_qend));
([^{}\r\n\[\]]+)|[^{}\r\n] {
buf_strnappend(&top_buf, yytext, yyleng);
}
<<EOF>> {
linenum = brace_start_line;
synerr(_("Unmatched '{'"));
yyterminate();
}
}
<PICKUPDEF>{
{WS} /* separates name and definition */
{NOT_WS}[^\r\n]* {
if(yyleng < MAXLINE)
{
strlcpy( nmdef, yytext, sizeof(nmdef) );
}
else
{
format_synerr( _("Definition value for {%s} too long\n"), nmstr);
FLEX_EXIT(EXIT_FAILURE);
}
/* Skip trailing whitespace. */
{
size_t i = strlen( nmdef );
while (i > 0 && (nmdef[i-1] == ' ' || nmdef[i-1] == '\t'))
--i;
nmdef[i] = '\0';
}
ndinstal( nmstr, nmdef );
didadef = true;
}
{NL} {
if ( ! didadef )
synerr( _( "incomplete name definition" ) );
BEGIN(INITIAL);
++linenum;
}
}
<OPTION>{
{NL} ++linenum; BEGIN(INITIAL);
{WS} option_sense = true;
"=" return '=';
no option_sense = ! option_sense;
7bit csize = option_sense ? 128 : 256;
8bit csize = option_sense ? 256 : 128;
align long_align = option_sense;
always-interactive {
ACTION_M4_IFDEF( "M4""_YY_ALWAYS_INTERACTIVE", option_sense );
interactive = option_sense;
}
array yytext_is_array = option_sense;
backup backing_up_report = option_sense;
batch interactive = ! option_sense;
bison-bridge bison_bridge_lval = option_sense;
bison-locations { if((bison_bridge_lloc = option_sense))
bison_bridge_lval = true;
}
"c++" C_plus_plus = option_sense;
caseful|case-sensitive sf_set_case_ins(!option_sense);
caseless|case-insensitive sf_set_case_ins(option_sense);
debug ddebug = option_sense;
default spprdflt = ! option_sense;
ecs useecs = option_sense;
fast {
useecs = usemecs = false;
use_read = fullspd = true;
}
full {
useecs = usemecs = false;
use_read = fulltbl = true;
}
input ACTION_IFDEF("YY_NO_INPUT", ! option_sense);
interactive interactive = option_sense;
lex-compat lex_compat = option_sense;
posix-compat posix_compat = option_sense;
line gen_line_dirs = option_sense;
main {
ACTION_M4_IFDEF( "M4""_YY_MAIN", option_sense);
/* Override yywrap */
if( option_sense == true )
do_yywrap = false;
}
meta-ecs usemecs = option_sense;
never-interactive {
ACTION_M4_IFDEF( "M4""_YY_NEVER_INTERACTIVE", option_sense );
interactive = !option_sense;
}
perf-report performance_report += option_sense ? 1 : -1;
pointer yytext_is_array = ! option_sense;
read use_read = option_sense;
reentrant reentrant = option_sense;
reject reject_really_used = option_sense;
stack ACTION_M4_IFDEF( "M4""_YY_STACK_USED", option_sense );
stdinit do_stdinit = option_sense;
stdout use_stdout = option_sense;
unistd ACTION_IFDEF("YY_NO_UNISTD_H", ! option_sense);
unput ACTION_M4_IFDEF("M4""_YY_NO_UNPUT", ! option_sense);
verbose printstats = option_sense;
warn nowarn = ! option_sense;
yylineno do_yylineno = option_sense; ACTION_M4_IFDEF("M4""_YY_USE_LINENO", option_sense);
yymore yymore_really_used = option_sense;
yywrap do_yywrap = option_sense;
yy_push_state ACTION_M4_IFDEF("M4""_YY_NO_PUSH_STATE", ! option_sense);
yy_pop_state ACTION_M4_IFDEF("M4""_YY_NO_POP_STATE", ! option_sense);
yy_top_state ACTION_M4_IFDEF("M4""_YY_NO_TOP_STATE", ! option_sense);
yy_scan_buffer ACTION_M4_IFDEF("M4""_YY_NO_SCAN_BUFFER", ! option_sense);
yy_scan_bytes ACTION_M4_IFDEF("M4""_YY_NO_SCAN_BYTES", ! option_sense);
yy_scan_string ACTION_M4_IFDEF("M4""_YY_NO_SCAN_STRING", ! option_sense);
yyalloc ACTION_M4_IFDEF("M4""_YY_NO_FLEX_ALLOC", ! option_sense);
yyrealloc ACTION_M4_IFDEF("M4""_YY_NO_FLEX_REALLOC", ! option_sense);
yyfree ACTION_M4_IFDEF("M4""_YY_NO_FLEX_FREE", ! option_sense);
yyget_debug ACTION_M4_IFDEF("M4""_YY_NO_GET_DEBUG", ! option_sense);
yyset_debug ACTION_M4_IFDEF("M4""_YY_NO_SET_DEBUG", ! option_sense);
yyget_extra ACTION_M4_IFDEF("M4""_YY_NO_GET_EXTRA", ! option_sense);
yyset_extra ACTION_M4_IFDEF("M4""_YY_NO_SET_EXTRA", ! option_sense);
yyget_leng ACTION_M4_IFDEF("M4""_YY_NO_GET_LENG", ! option_sense);
yyget_text ACTION_M4_IFDEF("M4""_YY_NO_GET_TEXT", ! option_sense);
yyget_lineno ACTION_M4_IFDEF("M4""_YY_NO_GET_LINENO", ! option_sense);
yyset_lineno ACTION_M4_IFDEF("M4""_YY_NO_SET_LINENO", ! option_sense);
yyget_in ACTION_M4_IFDEF("M4""_YY_NO_GET_IN", ! option_sense);
yyset_in ACTION_M4_IFDEF("M4""_YY_NO_SET_IN", ! option_sense);
yyget_out ACTION_M4_IFDEF("M4""_YY_NO_GET_OUT", ! option_sense);
yyset_out ACTION_M4_IFDEF("M4""_YY_NO_SET_OUT", ! option_sense);
yyget_lval ACTION_M4_IFDEF("M4""_YY_NO_GET_LVAL", ! option_sense);
yyset_lval ACTION_M4_IFDEF("M4""_YY_NO_SET_LVAL", ! option_sense);
yyget_lloc ACTION_M4_IFDEF("M4""_YY_NO_GET_LLOC", ! option_sense);
yyset_lloc ACTION_M4_IFDEF("M4""_YY_NO_SET_LLOC", ! option_sense);
extra-type return TOK_EXTRA_TYPE;
outfile return TOK_OUTFILE;
prefix return TOK_PREFIX;
yyclass return TOK_YYCLASS;
header(-file)? return TOK_HEADER_FILE;
tables-file return TOK_TABLES_FILE;
tables-verify {
tablesverify = option_sense;
if(!tablesext && option_sense)
tablesext = true;
}
\"[^"\n]*\" {
if(yyleng-1 < MAXLINE)
{
strlcpy( nmstr, yytext + 1, sizeof(nmstr) );
}
else
{
synerr( _("Option line too long\n"));
FLEX_EXIT(EXIT_FAILURE);
}
nmstr[strlen( nmstr ) - 1] = '\0';
return NAME;
}
(([a-mo-z]|n[a-np-z])[[:alpha:]\-+]*)|. {
format_synerr( _( "unrecognized %%option: %s" ),
yytext );
BEGIN(RECOVER);
}
}
<RECOVER>.*{NL} ++linenum; BEGIN(INITIAL);
<SECT2PROLOG>{
^"%{".* ++bracelevel; yyless( 2 ); /* eat only %{ */
^"%}".* --bracelevel; yyless( 2 ); /* eat only %} */
^{WS} START_CODEBLOCK(true); /* indented code in prolog */
^{NOT_WS}.* {
/* non-indented code */
if ( bracelevel <= 0 ) {
/* not in %{ ... %} */
yyless( 0 ); /* put it all back */
yy_set_bol( 1 );
mark_prolog();
BEGIN(SECT2);
} else {
START_CODEBLOCK(true);
}
}
. ACTION_ECHO;
{NL} ++linenum; ACTION_ECHO;
<<EOF>> {
mark_prolog();
sectnum = 0;
yyterminate(); /* to stop the parser */
}
}
<SECT2>{
^{OPTWS}{NL} ++linenum; /* allow blank lines in section 2 */
^{OPTWS}"%{" {
indented_code = false;
doing_codeblock = true;
bracelevel = 1;
BEGIN(PERCENT_BRACE_ACTION);
}
^{OPTWS}"<" {
/* Allow "<" to appear in (?x) patterns. */
if (!sf_skip_ws())
BEGIN(SC);
return '<';
}
^{OPTWS}"^" return '^';
\" BEGIN(QUOTE); return '"';
"{"/[[:digit:]] {
BEGIN(NUM);
if ( lex_compat || posix_compat )
return BEGIN_REPEAT_POSIX;
else
return BEGIN_REPEAT_FLEX;
}
"$"/([[:blank:]]|{NL}) return '$';
{WS}"%{" {
bracelevel = 1;
BEGIN(PERCENT_BRACE_ACTION);
if ( in_rule )
{
doing_rule_action = true;
in_rule = false;
return '\n';
}
}
{WS}"|".*{NL} {
if (sf_skip_ws()){
/* We're in the middle of a (?x: ) pattern. */
/* Push back everything starting at the "|" */
int amt = (int) (strchr (yytext, '|') - yytext);
yyless(amt);
}
else {
add_action("]""]");
continued_action = true;
++linenum;
return '\n';
}
}
^{WS}"/*" {
if (sf_skip_ws()){
/* We're in the middle of a (?x: ) pattern. */
yy_push_state(COMMENT_DISCARD);
}
else{
yyless( yyleng - 2 ); /* put back '/', '*' */
bracelevel = 0;
continued_action = false;
BEGIN(ACTION);
}
}
^{WS} /* allow indented rules */ ;
{WS} {
if (sf_skip_ws()){
/* We're in the middle of a (?x: ) pattern. */
}
else{
/* This rule is separate from the one below because
* otherwise we get variable trailing context, so
* we can't build the scanner using -{f,F}.
*/
bracelevel = 0;
continued_action = false;
BEGIN(ACTION);
if ( in_rule )
{
doing_rule_action = true;
in_rule = false;
return '\n';
}
}
}
{OPTWS}{NL} {
if (sf_skip_ws()){
/* We're in the middle of a (?x: ) pattern. */
++linenum;
}
else{
bracelevel = 0;
continued_action = false;
BEGIN(ACTION);
unput( '\n' ); /* so <ACTION> sees it */
if ( in_rule )
{
doing_rule_action = true;
in_rule = false;
return '\n';
}
}
}
^{OPTWS}"<<EOF>>" |
"<<EOF>>" return EOF_OP;
^"%%".* {
sectnum = 3;
BEGIN(no_section3_escape ? SECT3_NOESCAPE : SECT3);
outn("/* Begin user sect3 */");
yyterminate(); /* to stop the parser */
}
"["({FIRST_CCL_CHAR}|{CCL_EXPR})({CCL_CHAR}|{CCL_EXPR})* {
int cclval;
if(yyleng < MAXLINE)
{
strlcpy( nmstr, yytext, sizeof(nmstr) );
}
else
{
synerr( _("Input line too long\n"));
FLEX_EXIT(EXIT_FAILURE);
}
/* Check to see if we've already encountered this
* ccl.
*/
if (0 /* <--- This "0" effectively disables the reuse of a
* character class (purely based on its source text).
* The reason it was disabled is so yacc/bison can parse
* ccl operations, such as ccl difference and union.
*/
&& (cclval = ccllookup( nmstr )) != 0 )
{
if ( input() != ']' )
synerr( _( "bad character class" ) );
yylval = cclval;
++cclreuse;
return PREVCCL;
}
else
{
/* We fudge a bit. We know that this ccl will
* soon be numbered as lastccl + 1 by cclinit.
*/
cclinstal( nmstr, lastccl + 1 );
/* Push back everything but the leading bracket
* so the ccl can be rescanned.
*/
yyless( 1 );
BEGIN(FIRSTCCL);
return '[';
}
}
"{-}" return CCL_OP_DIFF;
"{+}" return CCL_OP_UNION;
/* Check for :space: at the end of the rule so we don't
* wrap the expanded regex in '(' ')' -- breaking trailing
* context.
*/
"{"{NAME}"}"[[:space:]]? {
char *nmdefptr;
int end_is_ws, end_ch;
end_ch = yytext[yyleng-1];
end_is_ws = end_ch != '}' ? 1 : 0;
if(yyleng-1 < MAXLINE)
{
strlcpy( nmstr, yytext + 1, sizeof(nmstr) );
}
else
{
synerr( _("Input line too long\n"));
FLEX_EXIT(EXIT_FAILURE);
}
nmstr[yyleng - 2 - end_is_ws] = '\0'; /* chop trailing brace */
if ( (nmdefptr = ndlookup( nmstr )) == 0 )
format_synerr(
_( "undefined definition {%s}" ),
nmstr );
else
{ /* push back name surrounded by ()'s */
size_t len = strlen( nmdefptr );
if (end_is_ws)
unput(end_ch);
if ( lex_compat || nmdefptr[0] == '^' ||
(len > 0 && nmdefptr[len - 1] == '$')
|| (end_is_ws && trlcontxt && !sf_skip_ws()))
{ /* don't use ()'s after all */
PUT_BACK_STRING(nmdefptr, 0);
if ( nmdefptr[0] == '^' )
BEGIN(CARETISBOL);
}
else
{
unput(')');
PUT_BACK_STRING(nmdefptr, 0);
unput('(');
}
}
}
"/*" {
if (sf_skip_ws())
yy_push_state(COMMENT_DISCARD);
else{
/* Push back the "*" and return "/" as usual. */
yyless(1);
return '/';
}
}
"(?#" {
if (lex_compat || posix_compat){
/* Push back the "?#" and treat it like a normal parens. */
yyless(1);
sf_push();
return '(';
}
else
yy_push_state(EXTENDED_COMMENT);
}
"(?" {
sf_push();
if (lex_compat || posix_compat)
/* Push back the "?" and treat it like a normal parens. */
yyless(1);
else
BEGIN(GROUP_WITH_PARAMS);
return '(';
}
"(" sf_push(); return '(';
")" {
if (_sf_top_ix > 0) {
sf_pop();
return ')';
} else
synerr(_("unbalanced parenthesis"));
}
[/|*+?.(){}] return (unsigned char) yytext[0];
. RETURNCHAR;
}
<SC>{
{OPTWS}{NL}{OPTWS} ++linenum; /* Allow blank lines & continuations */
[,*] return (unsigned char) yytext[0];
">" BEGIN(SECT2); return '>';
">"/^ BEGIN(CARETISBOL); return '>';
{SCNAME} RETURNNAME;
. {
format_synerr( _( "bad <start condition>: %s" ),
yytext );
}
}
<CARETISBOL>"^" BEGIN(SECT2); return '^';
<QUOTE>{
[^"\n] RETURNCHAR;
\" BEGIN(SECT2); return '"';
{NL} {
synerr( _( "missing quote" ) );
BEGIN(SECT2);
++linenum;
return '"';
}
}
<GROUP_WITH_PARAMS>{
":" BEGIN(SECT2);
"-" BEGIN(GROUP_MINUS_PARAMS);
i sf_set_case_ins(1);
s sf_set_dot_all(1);
x sf_set_skip_ws(1);
}
<GROUP_MINUS_PARAMS>{
":" BEGIN(SECT2);
i sf_set_case_ins(0);
s sf_set_dot_all(0);
x sf_set_skip_ws(0);
}
<FIRSTCCL>{
"^"/[^-\]\n] BEGIN(CCL); return '^';
"^"/("-"|"]") return '^';
. BEGIN(CCL); RETURNCHAR;
}
<CCL>{
-/[^\]\n] return '-';
[^\]\n] RETURNCHAR;
"]" BEGIN(SECT2); return ']';
.|{NL} {
synerr( _( "bad character class" ) );
BEGIN(SECT2);
return ']';
}
}
<FIRSTCCL,CCL>{
"[:alnum:]" BEGIN(CCL); return CCE_ALNUM;
"[:alpha:]" BEGIN(CCL); return CCE_ALPHA;
"[:blank:]" BEGIN(CCL); return CCE_BLANK;
"[:cntrl:]" BEGIN(CCL); return CCE_CNTRL;
"[:digit:]" BEGIN(CCL); return CCE_DIGIT;
"[:graph:]" BEGIN(CCL); return CCE_GRAPH;
"[:lower:]" BEGIN(CCL); return CCE_LOWER;
"[:print:]" BEGIN(CCL); return CCE_PRINT;
"[:punct:]" BEGIN(CCL); return CCE_PUNCT;
"[:space:]" BEGIN(CCL); return CCE_SPACE;
"[:upper:]" BEGIN(CCL); return CCE_UPPER;
"[:xdigit:]" BEGIN(CCL); return CCE_XDIGIT;
"[:^alnum:]" BEGIN(CCL); return CCE_NEG_ALNUM;
"[:^alpha:]" BEGIN(CCL); return CCE_NEG_ALPHA;
"[:^blank:]" BEGIN(CCL); return CCE_NEG_BLANK;
"[:^cntrl:]" BEGIN(CCL); return CCE_NEG_CNTRL;
"[:^digit:]" BEGIN(CCL); return CCE_NEG_DIGIT;
"[:^graph:]" BEGIN(CCL); return CCE_NEG_GRAPH;
"[:^lower:]" BEGIN(CCL); return CCE_NEG_LOWER;
"[:^print:]" BEGIN(CCL); return CCE_NEG_PRINT;
"[:^punct:]" BEGIN(CCL); return CCE_NEG_PUNCT;
"[:^space:]" BEGIN(CCL); return CCE_NEG_SPACE;
"[:^upper:]" BEGIN(CCL); return CCE_NEG_UPPER;
"[:^xdigit:]" BEGIN(CCL); return CCE_NEG_XDIGIT;
{CCL_EXPR} {
format_synerr(
_( "bad character class expression: %s" ),
yytext );
BEGIN(CCL); return CCE_ALNUM;
}
}
<NUM>{
[[:digit:]]+ {
yylval = myctoi( yytext );
return NUMBER;
}
"," return ',';
"}" {
BEGIN(SECT2);
if ( lex_compat || posix_compat )
return END_REPEAT_POSIX;
else
return END_REPEAT_FLEX;
}
. {
synerr( _( "bad character inside {}'s" ) );
BEGIN(SECT2);
return '}';
}
{NL} {
synerr( _( "missing }" ) );
BEGIN(SECT2);
++linenum;
return '}';
}
}
<PERCENT_BRACE_ACTION>{
{OPTWS}"%}".* bracelevel = 0;
<ACTION>"/*" ACTION_ECHO; yy_push_state( CODE_COMMENT );
<CODEBLOCK,ACTION>{
"reject" {
ACTION_ECHO;
CHECK_REJECT(yytext);
}
"yymore" {
ACTION_ECHO;
CHECK_YYMORE(yytext);
}
}
. ACTION_ECHO;
{NL} {
++linenum;
ACTION_ECHO;
if (bracelevel <= 0 || (doing_codeblock && indented_code)) {
if ( doing_rule_action )
add_action( "\tYY_BREAK]""]\n" );
doing_rule_action = doing_codeblock = false;
BEGIN(SECT2);
}
}
}
/* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
<ACTION>{
"{" ACTION_ECHO; ++bracelevel;
"}" ACTION_ECHO; --bracelevel;
[^[:alpha:]_{}\"'/\n\[\]]+ ACTION_ECHO;
{NAME} ACTION_ECHO;
"'"([^\'\\\n]|\\.)"'" ACTION_ECHO; /* character constant */
"'" ACTION_ECHO; BEGIN(CHARACTER_CONSTANT);
\" ACTION_ECHO; BEGIN(ACTION_STRING);
{NL} {
++linenum;
ACTION_ECHO;
if (bracelevel <= 0) {
if ( doing_rule_action )
add_action( "\tYY_BREAK]""]\n" );
doing_rule_action = false;
BEGIN(SECT2);
}
}
. ACTION_ECHO;
}
<ACTION_STRING>{
[^\[\]\"\\\n]+ ACTION_ECHO;
\" ACTION_ECHO; BEGIN(ACTION);
}
<CHARACTER_CONSTANT>{
[^\[\]\'\\\n]+ ACTION_ECHO;
\' ACTION_ECHO; BEGIN(ACTION);
}
<ACTION_STRING,CHARACTER_CONSTANT>{
(\\\n)* ACTION_ECHO;
\\(\\\n)*. ACTION_ECHO;
{NL} ++linenum; ACTION_ECHO; if (bracelevel <= 0) { BEGIN(SECT2); } else { BEGIN(ACTION); }
. ACTION_ECHO;
}
<COMMENT,CODE_COMMENT,COMMENT_DISCARD,ACTION,ACTION_STRING,CHARACTER_CONSTANT><<EOF>> {
synerr( _( "EOF encountered inside an action" ) );
yyterminate();
}
<EXTENDED_COMMENT,GROUP_WITH_PARAMS,GROUP_MINUS_PARAMS><<EOF>> {
synerr( _( "EOF encountered inside pattern" ) );
yyterminate();
}
<SECT2,QUOTE,FIRSTCCL,CCL>{ESCSEQ} {
yylval = myesc( (unsigned char *) yytext );
if ( YY_START == FIRSTCCL )
BEGIN(CCL);
return CHAR;
}
<SECT3>{
{M4QSTART} fputs(escaped_qstart, yyout);
{M4QEND} fputs(escaped_qend, yyout);
[^\[\]]* ECHO;
[][] ECHO;
<<EOF>> {
sectnum = 0;
yyterminate();
}
}
<SECT3_NOESCAPE>{
{M4QSTART} fprintf(yyout, "[""[%s]""]", escaped_qstart);
{M4QEND} fprintf(yyout, "[""[%s]""]", escaped_qend);
[^][]* ECHO;
[][] ECHO;
<<EOF>> {
sectnum = 0;
yyterminate();
}
}
<*>.|\n format_synerr( _( "bad character: %s" ), yytext );
%%
int yywrap(void)
{
if ( --num_input_files > 0 )
{
set_input_file( *++input_files );
return 0;
}
else
return 1;
}
/* set_input_file - open the given file (if NULL, stdin) for scanning */
void set_input_file( char *file )
{
if ( file && strcmp( file, "-" ) )
{
infilename = xstrdup(file);
yyin = fopen( infilename, "r" );
if ( yyin == NULL )
lerr( _( "can't open %s" ), file );
}
else
{
yyin = stdin;
infilename = xstrdup("<stdin>");
}
linenum = 1;
}