%{ /* Lex code for the Frame-CG parser */

#define MAX_INCLUDE_DEPTH 10
static YY_BUFFER_STATE fcgIncludedBuffers[MAX_INCLUDE_DEPTH];
static int fcgInclBufferNum=0;

static void cutAfterNumber ();
%}

ANY         (.|\n)
DIGIT       [0-9]
ISALNUM_    [A-Za-z0-9_¡-ÿ]
S           ([ \t\r ]|"&nbsp;")+
s           ([ \n\t\r ]|"&nbsp;")*
NUM         ({DIGIT}+("."{DIGIT}*)?)

IDENT1      ({ISALNUM_}|"#"({ISALNUM_}|"."))
IDENTx      ({ISALNUM_}|[\-/.~#%$@'!?&]|"\\"{ANY}|":_")
IDENTz      ({ISALNUM_}|[\-.~#%$@'!?&]|"\\"{ANY}|":_")
IDENTn      ({IDENTx}|"&"[a-z]+";"|"&#"{DIGIT}+";"|";"{IDENTz}|"#*"|"|")
URL         "://"({IDENTn}|[*+=]|","{IDENTx}|":"[0-9])+
IDENT       {IDENT1}({IDENTn})*{URL}?

VARVALUESTR ("$"{ISALNUM_}({IDENTn})*)
VARIA       (("?"|"*"|"@"|"^"){ISALNUM_}{IDENTn}*)

NUMERAL      ("+"|"-")?{NUM}
NUM_ORDER    {DIGIT}+("st"|"nd"|"rd"|"th")
TIME_STR     ({DIGIT}{DIGIT}?":"{DIGIT}{DIGIT}(":"{DIGIT}{DIGIT})?)
DATE_STR     (({DIGIT}{DIGIT}?"/")?{DIGIT}{DIGIT}?"/""-"?{DIGIT}{DIGIT}?{DIGIT}?{DIGIT}?(" "{TIME_STR})?)
IDENT__OPER  ({IDENT}|"!="|"<="|"=<"|"=>"|"<=>"|"="|"=<"|">="|">")

END_NODE    {s}(","|"]"|"}"|"or"|"and")

ANNOT_ALL   "(^"([^\^]|(\^[^\)]))*"^)"
ANNOT_END       ([^\^]|(\^[^\)]))*"^)"
DELIM_STR   "$("([^\)]|(\)[^\$]))*")$"
DELIM_END       ([^\)]|(\)[^\$]))*")$"
CODE_STR    "@("([^\)]|(\)[^\@]))*")@"
CODE_END        ([^\)]|(\)[^\@]))*")@"
QSTR1      \'([^'\\]|(\\{ANY}))*\'
QSTR1_END    ([^'\\]|(\\{ANY}))*\'
QSTR2      \"([^"\\]|(\\{ANY}))*\"
QSTR2_END    ([^"\\]|(\\{ANY}))*\"

QSTR        ({QSTR1}|{QSTR2})
ANY_VALUE   ({IDENT__OPER}|{QSTR})


%x TAG_BODY ANNOT1 CODESTR C_COMM

%%
{S}	            ;/* " */
"\n"                LineNumber++;
"//"[^\n]*          ;/* skip C++ line comments */
"<!--"              ;/* content of HTML comments parsed */
"-->"               ;
"<!"		    BEGIN(TAG_BODY);
"</"		    BEGIN(TAG_BODY);
"<"[A-Za-z]         BEGIN(TAG_BODY);
<TAG_BODY>">"       BEGIN(0);
<TAG_BODY>{QSTR}    LineNumber+=nbLinesInStr(fcgtext);
<TAG_BODY>"\n"      LineNumber++;
<TAG_BODY>.         ;
<TAG_BODY><<EOF>>   {putsErr("Tag not closed: '>' expected"); BEGIN(0);}

"/*"                BEGIN(C_COMM); /* more efficient than yyinput() */
<C_COMM>"\n"        LineNumber++;
<C_COMM>"*/"        BEGIN(0);
<C_COMM>.           ;
<C_COMM><<EOF>>     {putsErr("Multi-line comment not closed: \"*/\" expected");
                     BEGIN(0);};

"<=>"               return EQUIV;
"<="	            return IMPLIED_BY;
"=>"                return IMPLIES;
"=<"                return LTE;
">="                return GTE;
"!="                return NEQ;
"=="                return '=';
"\\\\="             return TERM_GUESS_MARK;
"\\\\"              return TYPE_CONSTR_MARK;

"(^"                BEGIN(ANNOT1);
<ANNOT1>{ANNOT_END} {LineNumber+=nbLinesInStr(fcgtext);
                     fcgtext[fcgleng-2]='\0';BEGIN(0);return ANNOTATION;}
<ANNOT1><<EOF>>     {putsErr("Annotation not closed: \"^)\" expected"); BEGIN(0);
                     return ANNOTATION;}

"@("                {CG_source.clear(); BEGIN(CODESTR);}
<CODESTR>"\n"       {LineNumber++; CG_source.append('\n');}
<CODESTR>")@"       {if (!CG_source.size) CG_source.append('@');
                     BEGIN(0); return CODE_STRING;
                     /*CODE_END doesn't work well*/}
<CODESTR>.          {CG_source.append(fcgtext[0]);/*for "@(..))@" to be parsed*/}
<CODESTR><<EOF>>    {putsErr("Unterminated string: \")@\" expected");BEGIN(0);
                     return STRING;}

{DELIM_STR}         {LineNumber+=nbLinesInStr(fcgtext);
                     /*fsDelSpacesAtEndOfFcgtext();*/
                     if (!strchr(fcgtext+2,'\"'))
                     { fcgtext[0]='\"'; memmove(fcgtext+1,fcgtext+2,fcgleng-2);
                       fcgtext[fcgleng-2]='\"'; fcgtext[fcgleng-1]='\0'; }
                     else if (!strchr(fcgtext+2,'\''))
                     { fcgtext[0]='\''; memmove(fcgtext+1,fcgtext+2,fcgleng-2);
                       fcgtext[fcgleng-2]='\''; fcgtext[fcgleng-1]='\0';
                     }return STRING;
                    }

{QSTR1}             {LineNumber+=nbLinesInStr(fcgtext);
                     if (!strpbrk(fcgtext," \n\r\t")) return IDENTIFIER;
                     if (!strchr(fcgtext,'\"'))
                     {fcgtext[0]='\"';fcgtext[fcgleng-1]='"';} return STRING;
                    }
{QSTR2}             {LineNumber+=nbLinesInStr(fcgtext); return STRING;}
{DATE_STR}          return POINT_IN_TIME;
{TIME_STR}          return PERIOD;
{NUMERAL}           {strcpy(TmpBuff,fcgtext);return NUMBER;
                     /*this rule must be before {IDENT} */}
{NUM_ORDER}{S}      {cutAfterNumber(); return ELEM_ORDER;}
{NUM_ORDER}" occurence of"{S}  {cutAfterNumber(); return ELEM_ORDER_OCCURENCE_OF;}

"{("                return CCB; /* Closed Collection Beginning */
")}"                return CCE; /* Closed Collection End */

"about"{S}          return ABOUT;
"at least"{S}       return AT_LEAST;
"at most"{S}        return AT_MOST;
"an"{S}             return A;
"a"{S}              return A;
"there is a"{S}     return A;
"there is an"{S}    return A;
"a typical"{S}      return MOST;
"certain"{S}        return CERTAIN;
"some"{S}           return SOME;
"several"{S}        return SEVERAL;
"the"{S}            return THE;
"any"{S}            return ANY;
"every"{S}          return ANY;
"all"{S}            return ANY;
"no"{S}             return NO;
"most"{S}           return MOST;
"mostly"{S}         return MOSTLY;

"each of"{S}"the"{S} return EACH_OF;
"each of"{S}        return EACH_OF;
"together"{S}       return TOGETHER;
"group of"{S}       return GROUP_OF;
"bag of"{S}         return BAG_OF;
"set of"{S}         return SET_OF;
"list of"{S}        return SEQUENCE_OF;
"sequence of"{S}    return SEQUENCE_OF;
"alternatives"{S}   return ALTERNATIVES;
"alternative"{S}    return ALTERNATIVES;

"BAG"               return BAG_C;
"SET"               return SET_C;
"LIST"              return LIST_C;
"SEQ"               return SEQ_C;
"XOR"               return XOR_C;
"OR"                return OR_C;
"AND"               return AND_C;

"and"{S}            return AND;
"&&"                return AND;
"or"{S}             return OR;
"||"                return OR;
"not"               return '!';
"mod"{S}            return MOD;

"between:"{S}       {yyless(7);return IDENTIFIER;}
"between :"{S}      {yyless(7);return IDENTIFIER;}
"between"{S}        return BETWEEN;
"from"{S}           ;/*return FROM;*/
"to"{S}{NUMERAL}{END_NODE}  {yyless(2);return TO_NUM;}
"to"{S}             return TO;
"and"{S}{NUMERAL}{END_NODE} {yyless(3);return AND_NUM;}

"tens"{S}           return TENS;
"dozens"{S}         return DOZENS;
"hundreds"{S}       return HUNDREDS;
"thousands"{S}      return THOUSANDS;
"millions"{S}       return MILLIONS;
"billions"{S}       return BILLIONS;
"many"{S}           return MANY;
"few"{S}            return FEW;
"a few"{S}          return A_FEW;

"good"{S}           return GOOD;
"bad"{S}            return BAD;
"important"{S}      return IMPORTANT;
"small"{S}          return SMALL;
"big"{S}            return BIG;
"great"{S}          return GREAT;

"of"                return OF;
"may"{S}            return MAY;
"can"{S}            return CAN;
"able to"{S}        return CAN;
"has for"{S}        ;
"have for"{S}       ;
"is"{S}             ;
"are"{S}            ;
"be"{S}             ;

"type"{S}           return TYPE;
"relation"{S}       return TYPE;
"function"{S}       return FUNCTION;
":->"               return FCT_RESULT;
":="                return NSC;
":=>"               return NC;
":<="               return SC;

"if"                return IF;
"then"              return THEN;
"else"              return ELSE;

{VARIA}             {if (fcgtext[0]=='?') fcgtext[0]='*';  return VARIABLE;}
{IDENT}             return IDENTIFIER;

.                   {return fcgtext[0];}

%%
void cutAfterNumber ()
{ char c, *s=fcgtext; 
  while ((c= *s)) if (isdigit(c)) s++; else { *s='\0'; break; }
}
