oql-parser.y 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. This is a LALR(1) grammar
  3. (seek for Lemon grammar to get some documentation from the Net)
  4. That doc was helpful: http://www.hwaci.com/sw/lemon/lemon.html
  5. To handle operators precedence we could have used the %left directive
  6. (we took another option, because that one was discovered right after...
  7. which option is the best for us?)
  8. Example:
  9. %left LOG_AND.
  10. %left LOG_OR.
  11. %nonassoc EQ NE GT GE LT LE.
  12. %left PLUS MINUS.
  13. %left TIMES DIVIDE MOD.
  14. %right EXP NOT.
  15. TODO : solve the 2 remaining shift-reduce conflicts (JOIN)
  16. */
  17. %name OQLParser_
  18. %declare_class {class OQLParserRaw}
  19. %syntax_error {
  20. throw new OQLParserException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN);
  21. }
  22. result ::= union(X). { $this->my_result = X; }
  23. result ::= query(X). { $this->my_result = X; }
  24. result ::= condition(X). { $this->my_result = X; }
  25. union(A) ::= query(X) UNION query(Y). {
  26. A = new OqlUnionQuery(X, Y);
  27. }
  28. union(A) ::= query(X) UNION union(Y). {
  29. A = new OqlUnionQuery(X, Y);
  30. }
  31. query(A) ::= SELECT class_name(X) join_statement(J) where_statement(W). {
  32. A = new OqlObjectQuery(X, X, W, J, array(X));
  33. }
  34. query(A) ::= SELECT class_name(X) AS_ALIAS class_name(Y) join_statement(J) where_statement(W). {
  35. A = new OqlObjectQuery(X, Y, W, J, array(Y));
  36. }
  37. query(A) ::= SELECT class_list(E) FROM class_name(X) join_statement(J) where_statement(W). {
  38. A = new OqlObjectQuery(X, X, W, J, E);
  39. }
  40. query(A) ::= SELECT class_list(E) FROM class_name(X) AS_ALIAS class_name(Y) join_statement(J) where_statement(W). {
  41. A = new OqlObjectQuery(X, Y, W, J, E);
  42. }
  43. class_list(A) ::= class_name(X). {
  44. A = array(X);
  45. }
  46. class_list(A) ::= class_list(L) COMA class_name(X). {
  47. array_push(L, X);
  48. A = L;
  49. }
  50. where_statement(A) ::= WHERE condition(C). { A = C;}
  51. where_statement(A) ::= . { A = null;}
  52. join_statement(A) ::= join_item(J) join_statement(S). {
  53. // insert the join statement on top of the existing list
  54. array_unshift(S, J);
  55. // and return the updated array
  56. A = S;
  57. }
  58. join_statement(A) ::= join_item(J). {
  59. A = Array(J);
  60. }
  61. join_statement(A) ::= . { A = null;}
  62. join_item(A) ::= JOIN class_name(X) AS_ALIAS class_name(Y) ON join_condition(C).
  63. {
  64. // create an array with one single item
  65. A = new OqlJoinSpec(X, Y, C);
  66. }
  67. join_item(A) ::= JOIN class_name(X) ON join_condition(C).
  68. {
  69. // create an array with one single item
  70. A = new OqlJoinSpec(X, X, C);
  71. }
  72. join_condition(A) ::= field_id(X) EQ field_id(Y). { A = new BinaryOqlExpression(X, '=', Y); }
  73. join_condition(A) ::= field_id(X) BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW', Y); }
  74. join_condition(A) ::= field_id(X) BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'BELOW_STRICT', Y); }
  75. join_condition(A) ::= field_id(X) NOT_BELOW field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW', Y); }
  76. join_condition(A) ::= field_id(X) NOT_BELOW_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_BELOW_STRICT', Y); }
  77. join_condition(A) ::= field_id(X) ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE', Y); }
  78. join_condition(A) ::= field_id(X) ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'ABOVE_STRICT', Y); }
  79. join_condition(A) ::= field_id(X) NOT_ABOVE field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE', Y); }
  80. join_condition(A) ::= field_id(X) NOT_ABOVE_STRICT field_id(Y). { A = new BinaryOqlExpression(X, 'NOT_ABOVE_STRICT', Y); }
  81. condition(A) ::= expression_prio4(X). { A = X; }
  82. expression_basic(A) ::= scalar(X). { A = X; }
  83. expression_basic(A) ::= field_id(X). { A = X; }
  84. expression_basic(A) ::= var_name(X). { A = X; }
  85. expression_basic(A) ::= func_name(X) PAR_OPEN arg_list(Y) PAR_CLOSE. { A = new FunctionOqlExpression(X, Y); }
  86. expression_basic(A) ::= PAR_OPEN expression_prio4(X) PAR_CLOSE. { A = X; }
  87. expression_basic(A) ::= expression_basic(X) list_operator(Y) list(Z). { A = new BinaryOqlExpression(X, Y, Z); }
  88. expression_prio1(A) ::= expression_basic(X). { A = X; }
  89. expression_prio1(A) ::= expression_prio1(X) operator1(Y) expression_basic(Z). { A = new BinaryOqlExpression(X, Y, Z); }
  90. expression_prio2(A) ::= expression_prio1(X). { A = X; }
  91. expression_prio2(A) ::= expression_prio2(X) operator2(Y) expression_prio1(Z). { A = new BinaryOqlExpression(X, Y, Z); }
  92. expression_prio3(A) ::= expression_prio2(X). { A = X; }
  93. expression_prio3(A) ::= expression_prio3(X) operator3(Y) expression_prio2(Z). { A = new BinaryOqlExpression(X, Y, Z); }
  94. expression_prio4(A) ::= expression_prio3(X). { A = X; }
  95. expression_prio4(A) ::= expression_prio4(X) operator4(Y) expression_prio3(Z). { A = new BinaryOqlExpression(X, Y, Z); }
  96. list(A) ::= PAR_OPEN list_items(X) PAR_CLOSE. {
  97. A = new ListOqlExpression(X);
  98. }
  99. list_items(A) ::= expression_prio4(X). {
  100. A = array(X);
  101. }
  102. list_items(A) ::= list_items(L) COMA expression_prio4(X). {
  103. array_push(L, X);
  104. A = L;
  105. }
  106. arg_list(A) ::= . {
  107. A = array();
  108. }
  109. arg_list(A) ::= argument(X). {
  110. A = array(X);
  111. }
  112. arg_list(A) ::= arg_list(L) COMA argument(X). {
  113. array_push(L, X);
  114. A = L;
  115. }
  116. argument(A) ::= expression_prio4(X). { A = X; }
  117. argument(A) ::= INTERVAL expression_prio4(X) interval_unit(Y). { A = new IntervalOqlExpression(X, Y); }
  118. interval_unit(A) ::= F_SECOND(X). { A = X; }
  119. interval_unit(A) ::= F_MINUTE(X). { A = X; }
  120. interval_unit(A) ::= F_HOUR(X). { A = X; }
  121. interval_unit(A) ::= F_DAY(X). { A = X; }
  122. interval_unit(A) ::= F_MONTH(X). { A = X; }
  123. interval_unit(A) ::= F_YEAR(X). { A = X; }
  124. scalar(A) ::= num_scalar(X). { A = X; }
  125. scalar(A) ::= str_scalar(X). { A = X; }
  126. num_scalar(A) ::= num_value(X). { A = new ScalarOqlExpression(X); }
  127. str_scalar(A) ::= str_value(X). { A = new ScalarOqlExpression(X); }
  128. field_id(A) ::= name(X). { A = new FieldOqlExpression(X); }
  129. field_id(A) ::= class_name(X) DOT name(Y). { A = new FieldOqlExpression(Y, X); }
  130. class_name(A) ::= name(X). { A=X; }
  131. var_name(A) ::= VARNAME(X). { A = new VariableOqlExpression(substr(X, 1)); }
  132. name(A) ::= NAME(X). {
  133. if (X[0] == '`')
  134. {
  135. $name = substr(X, 1, strlen(X) - 2);
  136. }
  137. else
  138. {
  139. $name = X;
  140. }
  141. A = new OqlName($name, $this->m_iColPrev);
  142. }
  143. num_value(A) ::= NUMVAL(X). {A=(int)X;}
  144. num_value(A) ::= MATH_MINUS NUMVAL(X). {A=(int)-X;}
  145. num_value(A) ::= HEXVAL(X). {A=new OqlHexValue(X);}
  146. str_value(A) ::= STRVAL(X). {A=stripslashes(substr(X, 1, strlen(X) - 2));}
  147. operator1(A) ::= num_operator1(X). {A=X;}
  148. operator1(A) ::= bitwise_operator1(X). {A=X;}
  149. operator2(A) ::= num_operator2(X). {A=X;}
  150. operator2(A) ::= str_operator(X). {A=X;}
  151. operator2(A) ::= REGEXP(X). {A=X;}
  152. operator2(A) ::= EQ(X). {A=X;}
  153. operator2(A) ::= NOT_EQ(X). {A=X;}
  154. operator3(A) ::= LOG_AND(X). {A=X;}
  155. operator3(A) ::= bitwise_operator3(X). {A=X;}
  156. operator4(A) ::= LOG_OR(X). {A=X;}
  157. operator4(A) ::= bitwise_operator4(X). {A=X;}
  158. num_operator1(A) ::= MATH_DIV(X). {A=X;}
  159. num_operator1(A) ::= MATH_MULT(X). {A=X;}
  160. num_operator2(A) ::= MATH_PLUS(X). {A=X;}
  161. num_operator2(A) ::= MATH_MINUS(X). {A=X;}
  162. num_operator2(A) ::= GT(X). {A=X;}
  163. num_operator2(A) ::= LT(X). {A=X;}
  164. num_operator2(A) ::= GE(X). {A=X;}
  165. num_operator2(A) ::= LE(X). {A=X;}
  166. str_operator(A) ::= LIKE(X). {A=X;}
  167. str_operator(A) ::= NOT_LIKE(X). {A=X;}
  168. bitwise_operator1(A) ::= BITWISE_LEFT_SHIFT(X). {A=X;}
  169. bitwise_operator1(A) ::= BITWISE_RIGHT_SHIFT(X). {A=X;}
  170. bitwise_operator3(A) ::= BITWISE_AND(X). {A=X;}
  171. bitwise_operator4(A) ::= BITWISE_OR(X). {A=X;}
  172. bitwise_operator4(A) ::= BITWISE_XOR(X). {A=X;}
  173. list_operator(A) ::= IN(X). {A=X;}
  174. list_operator(A) ::= NOT_IN(X). {A=X;}
  175. func_name(A) ::= F_IF(X). { A=X; }
  176. func_name(A) ::= F_ELT(X). { A=X; }
  177. func_name(A) ::= F_COALESCE(X). { A=X; }
  178. func_name(A) ::= F_ISNULL(X). { A=X; }
  179. func_name(A) ::= F_CONCAT(X). { A=X; }
  180. func_name(A) ::= F_SUBSTR(X). { A=X; }
  181. func_name(A) ::= F_TRIM(X). { A=X; }
  182. func_name(A) ::= F_DATE(X). { A=X; }
  183. func_name(A) ::= F_DATE_FORMAT(X). { A=X; }
  184. func_name(A) ::= F_CURRENT_DATE(X). { A=X; }
  185. func_name(A) ::= F_NOW(X). { A=X; }
  186. func_name(A) ::= F_TIME(X). { A=X; }
  187. func_name(A) ::= F_TO_DAYS(X). { A=X; }
  188. func_name(A) ::= F_FROM_DAYS(X). { A=X; }
  189. func_name(A) ::= F_YEAR(X). { A=X; }
  190. func_name(A) ::= F_MONTH(X). { A=X; }
  191. func_name(A) ::= F_DAY(X). { A=X; }
  192. func_name(A) ::= F_DATE_ADD(X). { A=X; }
  193. func_name(A) ::= F_DATE_SUB(X). { A=X; }
  194. func_name(A) ::= F_ROUND(X). { A=X; }
  195. func_name(A) ::= F_FLOOR(X). { A=X; }
  196. func_name(A) ::= F_INET_ATON(X). { A=X; }
  197. func_name(A) ::= F_INET_NTOA(X). { A=X; }
  198. %code {
  199. class OQLParserException extends OQLException
  200. {
  201. public function __construct($sInput, $iLine, $iCol, $sTokenName, $sTokenValue)
  202. {
  203. $sIssue = "Unexpected token $sTokenName";
  204. parent::__construct($sIssue, $sInput, $iLine, $iCol, $sTokenValue);
  205. }
  206. }
  207. class OQLParser extends OQLParserRaw
  208. {
  209. // dirty, but working for us (no other mean to get the final result :-(
  210. protected $my_result;
  211. public function GetResult()
  212. {
  213. return $this->my_result;
  214. }
  215. // More info on the source query and the current position while parsing it
  216. // Data used when an exception is raised
  217. protected $m_iLine; // still not used
  218. protected $m_iCol;
  219. protected $m_iColPrev; // this is the interesting one, because the parser will reduce on the next token
  220. protected $m_sSourceQuery;
  221. public function __construct($sQuery)
  222. {
  223. $this->m_iLine = 0;
  224. $this->m_iCol = 0;
  225. $this->m_iColPrev = 0;
  226. $this->m_sSourceQuery = $sQuery;
  227. // no constructor - parent::__construct();
  228. }
  229. public function doParse($token, $value, $iCurrPosition = 0)
  230. {
  231. $this->m_iColPrev = $this->m_iCol;
  232. $this->m_iCol = $iCurrPosition;
  233. return parent::DoParse($token, $value);
  234. }
  235. public function doFinish()
  236. {
  237. $this->doParse(0, 0);
  238. return $this->my_result;
  239. }
  240. public function __destruct()
  241. {
  242. // Bug in the original destructor, causing an infinite loop !
  243. // This is a real issue when a fatal error occurs on the first token (the error could not be seen)
  244. if (is_null($this->yyidx))
  245. {
  246. $this->yyidx = -1;
  247. }
  248. parent::__destruct();
  249. }
  250. }
  251. }