Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsexpressionlexer.ll 3 : : -------------------- 4 : : begin : August 2011 5 : : copyright : (C) 2011 by Martin Dobias 6 : : email : wonder.sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : %option noyywrap 17 : : %option case-insensitive 18 : : %option never-interactive 19 : : %option nounput 20 : : %option prefix="exp_" 21 : : // this makes flex generate lexer with context + init/destroy functions 22 : : %option reentrant 23 : : %option yylineno 24 : : // this makes Bison send yylex another argument to use instead of using the global variable yylval 25 : : %option bison-bridge 26 : : %option bison-locations 27 : : 28 : : 29 : : // ensure that lexer will be 8-bit (and not just 7-bit) 30 : : %option 8bit 31 : : 32 : : %{ 33 : : 34 : : #include <stdlib.h> // atof() 35 : : 36 : : #include "qgsexpression.h" 37 : : #include "expression/qgsexpressionnodeimpl.h" 38 : : #include "qgsexpressionfunction.h" 39 : : struct expression_parser_context; 40 : : #include "qgsexpressionparser.hpp" 41 : : #include <QLocale> 42 : : 43 : : // if not defined, searches for isatty() 44 : : // which doesn't in MSVC compiler 45 : : #define YY_NEVER_INTERACTIVE 1 46 : : 47 : : #ifndef YY_NO_UNPUT 48 : : #define YY_NO_UNPUT // unused 49 : : #endif 50 : : 51 : : #ifdef _MSC_VER 52 : : #define YY_NO_UNISTD_H 53 : : #endif 54 : : 55 : : #define B_OP(x) yylval->b_op = QgsExpressionNodeBinaryOperator::x 56 : : #define U_OP(x) yylval->u_op = QgsExpressionNodeUnaryOperator::x 57 : : #define TEXT yylval->text = new QString( QString::fromUtf8(yytext) ); 58 : : #define TEXT_FILTER(filter_fn) yylval->text = new QString( filter_fn( QString::fromUtf8(yytext) ) ); 59 : : 60 : : #define YY_USER_ACTION \ 61 : : yylloc->first_line = yylloc->last_line; \ 62 : : yylloc->first_column = yylloc->last_column; \ 63 : : for(int i = 0; yytext[i] != '\0'; i++) { \ 64 : : if(yytext[i] == '\n') { \ 65 : : yylloc->last_line++; \ 66 : : yylloc->last_column = 0; \ 67 : : } \ 68 : : else { \ 69 : : yylloc->last_column++; \ 70 : : } \ 71 : : } 72 : : 73 : 0 : static QString stripText(QString text) 74 : : { 75 : : // strip single quotes on start,end 76 : 0 : text = text.mid( 1, text.length() - 2 ); 77 : : 78 : : // make single "single quotes" from double "single quotes" 79 : 0 : text.replace( "''", "'" ); 80 : : 81 : : // strip \n \' etc. 82 : 0 : int index = 0; 83 : 0 : while (( index = text.indexOf( '\\', index ) ) != -1 ) 84 : : { 85 : 0 : text.remove( index, 1 ); // delete backslash 86 : 0 : QChar chr; 87 : 0 : switch ( text[index].toLatin1() ) // evaluate backslashed character 88 : : { 89 : 0 : case 'n': chr = '\n'; break; 90 : 0 : case 't': chr = '\t'; break; 91 : 0 : case '\\': chr = '\\'; break; 92 : 0 : case '\'': chr = '\''; break; 93 : 0 : default: chr = '?'; break; 94 : : } 95 : 0 : text[index++] = chr; // set new character and push index +1 96 : : } 97 : 0 : return text; 98 : 0 : } 99 : : 100 : 0 : static QString stripNamedText(QString text) 101 : : { 102 : 0 : text.remove(":="); 103 : 0 : return text.trimmed(); 104 : 0 : } 105 : : 106 : 0 : static QString stripColumnRef(QString text) 107 : : { 108 : : // strip double quotes on start,end 109 : 0 : text = text.mid( 1, text.length() - 2 ); 110 : : 111 : : // make single "double quotes" from double "double quotes" 112 : 0 : text.replace( "\"\"", "\"" ); 113 : 0 : return text; 114 : 0 : } 115 : : 116 : : // C locale for correct parsing of numbers even if the system locale is different 117 : 0 : Q_GLOBAL_STATIC_WITH_ARGS(QLocale, cLocale, ("C") ) 118 : : 119 : : %} 120 : : 121 : : %s BLOCK_COMMENT 122 : : 123 : : line_comment \-\-[^\r\n]*[\r\n]? 124 : : 125 : : white [ \t\r\n]+ 126 : : 127 : : non_ascii [\x80-\xFF] 128 : : 129 : : col_first [A-Za-z_]|{non_ascii} 130 : : col_next [A-Za-z0-9_]|{non_ascii} 131 : : identifier {col_first}{col_next}* 132 : : 133 : : deprecated_function "$"[xXyY]_?[aA][tT] 134 : : special_col "$"{identifier} 135 : : variable "@"{identifier} 136 : : 137 : : named_node {identifier}{white}*":="{white}* 138 : : 139 : : col_str_char "\"\""|[^\"] 140 : : identifier_quoted "\""{col_str_char}*"\"" 141 : : 142 : : dig [0-9] 143 : : num_int {dig}+ 144 : : num_float {dig}*(\.{dig}+([eE][-+]?{dig}+)?|[eE][-+]?{dig}+) 145 : : boolean "TRUE"|"FALSE" 146 : : 147 : : str_char ('')|(\\.)|[^'\\] 148 : : string "'"{str_char}*"'" 149 : : 150 : : %% 151 : : 152 : : <INITIAL>{ 153 : : "/*" BEGIN(BLOCK_COMMENT); 154 : : } 155 : : <BLOCK_COMMENT>{ 156 : : "*/" BEGIN(INITIAL); 157 : : [^*\n]+ // eat comment in chunks 158 : : "*" // eat the lone star 159 : : \n yylineno++; 160 : : } 161 : : 162 : : "NOT" { U_OP(uoNot); return NOT; } 163 : : "AND" { B_OP(boAnd); return AND; } 164 : : "OR" { B_OP(boOr); return OR; } 165 : : 166 : : "=" { B_OP(boEQ); return EQ; } 167 : : "!=" { B_OP(boNE); return NE; } 168 : : "<=" { B_OP(boLE); return LE; } 169 : : ">=" { B_OP(boGE); return GE; } 170 : : "<>" { B_OP(boNE); return NE; } 171 : : "<" { B_OP(boLT); return LT; } 172 : : ">" { B_OP(boGT); return GT; } 173 : : 174 : : "~" { B_OP(boRegexp); return REGEXP; } 175 : : "LIKE" { B_OP(boLike); return LIKE; } 176 : : "NOT"{white}"LIKE" { B_OP(boNotLike); return LIKE; } 177 : : "ILIKE" { B_OP(boILike); return LIKE; } 178 : : "NOT"{white}"ILIKE" { B_OP(boNotILike); return LIKE; } 179 : : "IS" { B_OP(boIs); return IS; } 180 : : "IS"{white}"NOT" { B_OP(boIsNot); return IS; } 181 : : "||" { B_OP(boConcat); return CONCAT; } 182 : : 183 : : "+" { B_OP(boPlus); return PLUS; } 184 : : "-" { B_OP(boMinus); return MINUS; } 185 : : "*" { B_OP(boMul); return MUL; } 186 : : "//" { B_OP(boIntDiv); return INTDIV; } 187 : : "/" { B_OP(boDiv); return DIV; } 188 : : "%" { B_OP(boMod); return MOD; } 189 : : "^" { B_OP(boPow); return POW; } 190 : : 191 : : "IN" { return IN; } 192 : : 193 : : "NULL" { return NULLVALUE; } 194 : : 195 : : "CASE" { return CASE; } 196 : : "WHEN" { return WHEN; } 197 : : "THEN" { return THEN; } 198 : : "ELSE" { return ELSE; } 199 : : "END" { return END; } 200 : : 201 : : [()\[\]] { return yytext[0]; } 202 : : 203 : : "," { return COMMA; } 204 : : 205 : : {num_float} { yylval->numberFloat = cLocale()->toDouble( QString::fromLatin1(yytext) ); return NUMBER_FLOAT; } 206 : : {num_int} { 207 : : bool ok; 208 : : yylval->numberInt = cLocale()->toInt( QString::fromLatin1(yytext), &ok ); 209 : : if( ok ) 210 : : return NUMBER_INT; 211 : : 212 : : yylval->numberInt64 = cLocale()->toLongLong( QString::fromLatin1(yytext), &ok ); 213 : : if( ok ) 214 : : return NUMBER_INT64; 215 : : 216 : : yylval->numberFloat = cLocale()->toDouble( QString::fromLatin1(yytext), &ok ); 217 : : if( ok ) 218 : : return NUMBER_FLOAT; 219 : : 220 : : return Unknown_CHARACTER; 221 : : } 222 : : 223 : : {boolean} { yylval->boolVal = QString( yytext ).compare( "true", Qt::CaseInsensitive ) == 0; return BOOLEAN; } 224 : : 225 : : {string} { TEXT_FILTER(stripText); return STRING; } 226 : : 227 : : {deprecated_function} { TEXT; return NAME; } 228 : : 229 : : {named_node} { TEXT_FILTER(stripNamedText); return NAMED_NODE; } 230 : : 231 : : {special_col} { TEXT; return SPECIAL_COL; } 232 : : 233 : : {variable} { TEXT; return VARIABLE; } 234 : : 235 : : {identifier} { TEXT; return NAME; } 236 : : 237 : : {identifier_quoted} { TEXT_FILTER(stripColumnRef); return QUOTED_COLUMN_REF; } 238 : : 239 : : {white} /* skip blanks and tabs */ 240 : : 241 : : {line_comment} /* skip line comments */ 242 : : 243 : : . { return Unknown_CHARACTER; } 244 : : 245 : : 246 : : %%