    %{
    #include "genfun.h"

    #if 0
    #define PUSH(s) \
            yy_push_state(s); \
            generateNewLine(); \
            generate_normal("<!-- PUSH  " #s " -->"); \
            generateNewLine();

    #define POP(s) \
            yy_pop_state(); \
            generateNewLine(); \
            generate_normal("<!-- POP   " #s " -->"); \
            generateNewLine();
    #else
        #define PUSH(s) yy_push_state(s);
        #define POP(s) yy_pop_state();
    #endif

    #define TRIMNORMAL(n)\
                do{ if(yyleng > n){\
                        yytext[yyleng - n]= '\0';\
                        generate_normal(yytext);\
                    }}while(0)
    %}

    %option stack nomain yylineno noyywrap nounput
    %option prefix="flex_scanner_"

    %x verbatim_code options name_def sc_decl in_string sect2 pattern
    %x comment sect2prolog start_cond sect3

    NL	        \r?\n
    OPTWS		[[:blank:]]*
    WS          [[:blank:]]
    NOT_WS		[^[:blank:]\r\n]
    NAME        [[:alpha:]_][[:alnum:]_-]*
    LEXOPT		[aceknopr]
    REGEXOP     [\*\.\+\?\/\^\(\|\)\]\[]
    NUMESCSEQ	\\(([0-7]{1,3})|x([[:xdigit:]]{1,2}))
    CCL1        alnum|alpha|ascii|blank|cntrl|digit|graph
    CCL2        lower|print|punct|space|upper|xdigit
    CCL         {CCL1}|{CCL2}

    %%
        int bracelevel=0;

    <INITIAL>{
        ^"%{"           generatePreProc(yytext); PUSH(verbatim_code);
        ^"%"[sx]        generatePreProc(yytext); PUSH(sc_decl);
        ^"%option"      generatePreProc(yytext); PUSH(options);
        ^"%array"    |
        ^"%pointer"  |
        ^"%"{LEXOPT}    generatePreProc(yytext);
        ^{NAME}         generateFunction(yytext); PUSH(name_def);
        ^"%%"           generatePreProc(yytext); BEGIN(sect2);
        "/*"            startComment(yytext); PUSH(comment);
        {NL}            generateNewLine();
        [^\n_[:alpha:]%\/]+     generate_normal(yytext);
        .               generate_normal(yytext);
    }
    <verbatim_code>{
        ^"%}"           generatePreProc(yytext); POP(verbatim_code);
        [^\r\n%]+       generate_normal(yytext);
        [%\r]           generate_normal(yytext);
        {NL}            generateNewLine();
    }
    <options>{
        {WS}+           generate_normal(yytext);
        {NAME}          generateKeyWord(yytext);
        "="             generateSymbol(yytext);
        \"[^\"\n]*\"     {
                            startString("\"");
                            if(yyleng> 2){
                                yytext[yyleng-1] = '\0';
                                generateString(yytext+1);
                            }
                            endString("\"");
                        }
        {NL}            generateNewLine(); POP(options);
        .               generate_normal(yytext);
    }
    <sc_decl>{
        {WS}+           generate_normal(yytext);
        {NAME}          generateFunction(yytext);
        {NL}            generateNewLine(); POP(sc_decl);
        .               generate_normal(yytext);
    }

    <name_def>{
        {WS}+           generate_normal(yytext);
        {NL}            generateNewLine(); yy_set_bol(1);POP(name_def);
        .               yyless(0); PUSH(pattern);
    }
    <pattern>{
        {WS}+           generate_normal(yytext); POP(pattern);
        {NL}            {
                            yy_set_bol(1);
                            yyless(0);
                            POP(pattern);
                        }
        "{"{NAME}"}"    {
                            generateSymbol("{");
                            yytext[yyleng-1] = '\0';
                            generateFunction(yytext+1);
                            generateSymbol("}");
                        }
        "\""            startString(yytext); PUSH(in_string);
        {REGEXOP}       generateSymbol(yytext);
        "<<EOF>>"       generateKeyWord(yytext);
        "[:"({CCL})":]"   {
                            generateSymbol("[:");
                            yytext[yyleng-2] = '\0';
                            generateKeyWord(yytext+2);
                            generateSymbol(":]");
                        }
        {NUMESCSEQ}     generateNumber(yytext);
        \\[^\n]         generatePreProc(yytext);
        .               generate_normal(yytext);
    }
    <in_string>{
        "\""            endString(yytext); POP(in_string);
        {NUMESCSEQ}     generateNumber(yytext);
        \\[^\n]         generatePreProc(yytext);
        {NL}            generateNewLine(); POP(in_string); /* actually an error */
        .               generateString(yytext);
    }
    <comment>{
        "*/"            endComment(yytext); POP(comment);
        [^*\n]+         generateComment(yytext);
        "*"             generateComment(yytext);
        {NL}            generateNewLine();
    }
    <sect2prolog>{
    	^"%{".*	        ++bracelevel; generatePreProc(yytext);
    	^"%}".*	        --bracelevel; generatePreProc(yytext);
    	^{WS}.+         generate_normal(yytext);

    	^{NOT_WS}.*	    {
                            if ( bracelevel <= 0 ) {
                                yyless( 0 );
                                yy_set_bol( 1 );
                                BEGIN(sect2);
                            }
                            else
                                generate_normal(yytext);
                        }

        {NL}            generateNewLine();
        .+              generate_normal(yytext);
    }
    <sect2>{
        "<"             generatePreProc(yytext); PUSH(start_cond);
    	"/*"	        startComment(yytext); PUSH(comment);
    	{WS}+		    generate_normal(yytext);
    	^"%%"           generatePreProc(yytext); BEGIN(sect3);
    	{NL}            generateNewLine();
        \}              generate_normal(yytext);
        .               yyless(0); PUSH(pattern);
    }
    <start_cond>{
        ">"             generatePreProc(yytext); POP(start_cond);
        ","             generate_normal(yytext);
        {NAME}|"*"      generateFunction(yytext);
        {NL}            generateNewLine();
        [^[:alpha:]_\n,>\*]+      generate_normal(yytext);
    }
    <sect3>{
        {NL}            generateNewLine();
        .+              generate_normal(yytext);
    }
    %%

    /* vim:set ft=flex expandtab cindent tabstop=4 softtabstop=4 shiftwidth=4 textwidth=0: */