%{
#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: */