| /* 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" |
| #include "parse.h" |
| extern bool tablesverify, tablesext; |
| extern int trlcontxt; /* Set in parse.y for each rule. */ |
| extern const char *escaped_qstart, *escaped_qend; |
| |
| #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) \ |
| { \ |
| strncpy( 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) |
| { |
| strncpy( 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) |
| { |
| strncpy( 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) |
| { |
| strncpy( 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) |
| { |
| strncpy( 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) |
| { |
| strncpy( 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; |
| } |