temporal_raster_operator.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. """
  2. Temporal operator evaluation with PLY
  3. (C) 2013 by the GRASS Development Team
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. :authors: Thomas Leppelt and Soeren Gebbert
  8. .. code-block:: python
  9. >>> p = TemporalRasterOperatorParser()
  10. >>> expression = "{equal| during | follows,+!:}"
  11. >>> p.parse(expression)
  12. >>> print(p.relations, p.temporal, p.function)
  13. (['equal', 'during', 'follows'], '+', '!:')
  14. >>> expression = "{equal| during,!:}"
  15. >>> p.parse(expression)
  16. >>> print(p.relations, p.temporal, p.function)
  17. (['equal', 'during'], '=', '!:')
  18. >>> expression = "{!:}"
  19. >>> p.parse(expression)
  20. >>> print(p.relations, p.temporal, p.function)
  21. (['equal'], '=', '!:')
  22. >>> expression = "{|#}"
  23. >>> p.parse(expression)
  24. >>> print(p.relations, p.temporal, p.function)
  25. (['equal'], '|', '#')
  26. >>> expression = "{equal|during,=!:}"
  27. >>> p.parse(expression)
  28. >>> print(p.relations, p.temporal, p.function)
  29. (['equal', 'during'], '=', '!:')
  30. >>> expression = "{equal|during|starts}"
  31. >>> p.parse(expression)
  32. >>> print(p.relations, p.temporal, p.function)
  33. (['equal', 'during', 'starts'], None, None)
  34. >>> expression = "{equal,++}"
  35. >>> p.parse(expression)
  36. >>> print(p.relations, p.temporal, p.function)
  37. (['equal'], '+', '+')
  38. >>> expression = "{equal | during,|%}"
  39. >>> p.parse(expression)
  40. >>> print(p.relations, p.temporal, p.function)
  41. (['equal', 'during'], '|', '%')
  42. >>> expression = "{||}"
  43. >>> p.parse(expression)
  44. >>> print(p.relations, p.temporal, p.function)
  45. (['equal'], '=', '||')
  46. >>> expression = "{equal,||}"
  47. >>> p.parse(expression)
  48. >>> print(p.relations, p.temporal, p.function)
  49. (['equal'], '=', '||')
  50. >>> expression = "{equal | during | contains,&&}"
  51. >>> p.parse(expression)
  52. >>> print(p.relations, p.temporal, p.function)
  53. (['equal', 'during', 'contains'], '=', '&&')
  54. >>> expression = "{equal | during | contains,/}"
  55. >>> p.parse(expression)
  56. >>> print(p.relations, p.temporal, p.function)
  57. (['equal', 'during', 'contains'], '=', '/')
  58. >>> expression = "{equal | during | contains,|*}"
  59. >>> p.parse(expression)
  60. >>> print(p.relations, p.temporal, p.function)
  61. (['equal', 'during', 'contains'], '|', '*')
  62. """
  63. try:
  64. import ply.lex as lex
  65. import ply.yacc as yacc
  66. except:
  67. pass
  68. class TemporalRasterOperatorLexer(object):
  69. """Lexical analyzer for the GRASS GIS temporal operator"""
  70. # Functions that defines topological relations.
  71. relations = {
  72. 'equal': "EQUAL",
  73. 'follows': "FOLLOWS",
  74. 'precedes': "PRECEDES",
  75. 'overlaps': "OVERLAPS",
  76. 'overlapped': "OVERLAPPED",
  77. 'during': "DURING",
  78. 'starts': "STARTS",
  79. 'finishes': "FINISHES",
  80. 'contains': "CONTAINS",
  81. 'started': "STARTED",
  82. 'finished': "FINISHED",
  83. 'over': "OVER"
  84. }
  85. # This is the list of token names.
  86. tokens = (
  87. 'COMMA',
  88. 'LEFTREF',
  89. 'HASH',
  90. 'OR',
  91. 'AND',
  92. 'MOD',
  93. 'DIV',
  94. 'MULT',
  95. 'ADD',
  96. 'SUB',
  97. 'T_SELECT',
  98. 'T_NOT_SELECT',
  99. 'CLPAREN',
  100. 'CRPAREN',
  101. )
  102. # Build the token list
  103. tokens = tokens + tuple(relations.values())
  104. # Regular expression rules for simple tokens
  105. t_T_SELECT = r':'
  106. t_T_NOT_SELECT = r'!:'
  107. t_COMMA = r','
  108. t_LEFTREF = r'='
  109. t_HASH = r'\#'
  110. t_OR = r'[\|]'
  111. t_AND = r'[&]'
  112. t_MOD = r'[\%]'
  113. t_DIV = r'[\/]'
  114. t_MULT = r'[\*]'
  115. t_ADD = r'[\+]'
  116. t_SUB = r'[-]'
  117. t_CLPAREN = r'\{'
  118. t_CRPAREN = r'\}'
  119. # These are the things that should be ignored.
  120. t_ignore = ' \t'
  121. # Track line numbers.
  122. def t_newline(self, t):
  123. r'\n+'
  124. t.lineno += len(t.value)
  125. def t_NAME(self, t):
  126. r'[a-zA-Z_][a-zA-Z_0-9]*'
  127. self.temporal_symbol(t)
  128. return t
  129. # Parse symbols
  130. def temporal_symbol(self, t):
  131. # Check for reserved words
  132. if t.value in TemporalRasterOperatorLexer.relations.keys():
  133. t.type = TemporalRasterOperatorLexer.relations.get(t.value)
  134. #else:
  135. # t.type = 'NAME'
  136. return(t)
  137. # Handle errors.
  138. def t_error(self, t):
  139. raise SyntaxError("syntax error on line %d near '%s'" %
  140. (t.lineno, t.value))
  141. # Build the lexer
  142. def build(self, **kwargs):
  143. self.lexer = lex.lex(module=self, **kwargs)
  144. # Just for testing
  145. def test(self, data):
  146. self.name_list = {}
  147. print(data)
  148. self.lexer.input(data)
  149. while True:
  150. tok = self.lexer.token()
  151. if not tok: break
  152. print tok
  153. ###############################################################################
  154. class TemporalRasterOperatorParser(object):
  155. """The temporal algebra class"""
  156. def __init__(self):
  157. self.lexer = TemporalRasterOperatorLexer()
  158. self.lexer.build()
  159. self.parser = yacc.yacc(module=self)
  160. def parse(self, expression, comparison=False):
  161. self.comparison = comparison
  162. self.parser.parse(expression)
  163. # Error rule for syntax errors.
  164. def p_error(self, t):
  165. raise SyntaxError("invalid syntax")
  166. # Get the tokens from the lexer class
  167. tokens = TemporalRasterOperatorLexer.tokens
  168. def p_relation_only(self, t):
  169. # The expression should always return a list of maps.
  170. """
  171. operator : CLPAREN relation CRPAREN
  172. | CLPAREN relationlist CRPAREN
  173. """
  174. # Set three operator components.
  175. if isinstance(t[2], list):
  176. self.relations = t[2]
  177. else:
  178. self.relations = [t[2]]
  179. self.temporal = None
  180. self.function = None
  181. t[0] = t[2]
  182. def p_operator(self, t):
  183. # The expression should always return a list of maps.
  184. """
  185. operator : CLPAREN select CRPAREN
  186. | CLPAREN HASH CRPAREN
  187. | CLPAREN arithmetic CRPAREN
  188. """
  189. # Set three operator components.
  190. self.relations = ['equal']
  191. self.temporal = "="
  192. self.function = t[2]
  193. t[0] = t[2]
  194. def p_comparison(self, t):
  195. # The expression should always return a list of maps.
  196. """
  197. operator : CLPAREN temporal AND CRPAREN
  198. | CLPAREN temporal OR CRPAREN
  199. """
  200. # Set three operator components.
  201. self.relations = ['equal']
  202. self.temporal = "="
  203. if t[2] == t[3]:
  204. self.function = t[2] + t[3]
  205. else:
  206. raise SyntaxError("syntax error on line %d near '%s'" %
  207. (t.lineno, t.value))
  208. t[0] = t[2]
  209. def p_operator_temporal(self, t):
  210. # The expression should always return a list of maps.
  211. """
  212. operator : CLPAREN temporal select CRPAREN
  213. | CLPAREN temporal HASH CRPAREN
  214. | CLPAREN temporal arithmetic CRPAREN
  215. """
  216. # Set three operator components.
  217. self.relations = ['equal']
  218. self.temporal = t[2]
  219. self.function = t[3]
  220. t[0] = t[3]
  221. def p_operator_relation(self, t):
  222. # The expression should always return a list of maps.
  223. """
  224. operator : CLPAREN relation COMMA select CRPAREN
  225. | CLPAREN relationlist COMMA select CRPAREN
  226. | CLPAREN relation COMMA HASH CRPAREN
  227. | CLPAREN relationlist COMMA HASH CRPAREN
  228. | CLPAREN relation COMMA arithmetic CRPAREN
  229. | CLPAREN relationlist COMMA arithmetic CRPAREN
  230. """
  231. # Set three operator components.
  232. if isinstance(t[2], list):
  233. self.relations = t[2]
  234. else:
  235. self.relations = [t[2]]
  236. self.temporal = "="
  237. self.function = t[4]
  238. t[0] = t[4]
  239. def p_comparison_relation(self, t):
  240. # The expression should always return a list of maps.
  241. """
  242. operator : CLPAREN relation COMMA temporal AND CRPAREN
  243. | CLPAREN relation COMMA temporal OR CRPAREN
  244. | CLPAREN relationlist COMMA temporal AND CRPAREN
  245. | CLPAREN relationlist COMMA temporal OR CRPAREN
  246. """
  247. # Set three operator components.
  248. if isinstance(t[2], list):
  249. self.relations = t[2]
  250. else:
  251. self.relations = [t[2]]
  252. self.temporal = "="
  253. if t[4] == t[5]:
  254. self.function = t[4] + t[5]
  255. else:
  256. raise SyntaxError("syntax error on line %d near '%s'" %
  257. (t.lineno, t.value))
  258. t[0] = t[4]
  259. def p_operator_relation_temporal(self, t):
  260. # The expression should always return a list of maps.
  261. """
  262. operator : CLPAREN relation COMMA temporal select CRPAREN
  263. | CLPAREN relationlist COMMA temporal select CRPAREN
  264. | CLPAREN relation COMMA temporal HASH CRPAREN
  265. | CLPAREN relationlist COMMA temporal HASH CRPAREN
  266. | CLPAREN relation COMMA temporal arithmetic CRPAREN
  267. | CLPAREN relationlist COMMA temporal arithmetic CRPAREN
  268. """
  269. # Set three operator components.
  270. if isinstance(t[2], list):
  271. self.relations = t[2]
  272. else:
  273. self.relations = [t[2]]
  274. self.temporal = t[4]
  275. self.function = t[5]
  276. t[0] = t[5]
  277. def p_relation(self, t):
  278. # The list of relations.
  279. """
  280. relation : EQUAL
  281. | FOLLOWS
  282. | PRECEDES
  283. | OVERLAPS
  284. | OVERLAPPED
  285. | DURING
  286. | STARTS
  287. | FINISHES
  288. | CONTAINS
  289. | STARTED
  290. | FINISHED
  291. """
  292. t[0] = t[1]
  293. def p_over(self, t):
  294. # The list of relations.
  295. """
  296. relation : OVER
  297. """
  298. over_list = ["overlaps", "overlapped"]
  299. t[0] = over_list
  300. def p_relationlist(self, t):
  301. # The list of relations.
  302. """
  303. relationlist : relation OR relation
  304. | relation OR relationlist
  305. """
  306. rel_list = []
  307. rel_list.append(t[1])
  308. if isinstance(t[3], list):
  309. rel_list = rel_list + t[3]
  310. else:
  311. rel_list.append(t[3])
  312. t[0] = rel_list
  313. def p_temporal_operator(self, t):
  314. # The list of relations.
  315. """
  316. temporal : LEFTREF
  317. | OR
  318. | AND
  319. | ADD
  320. """
  321. t[0] = t[1]
  322. def p_select_operator(self, t):
  323. # The list of relations.
  324. """
  325. select : T_SELECT
  326. | T_NOT_SELECT
  327. """
  328. t[0] = t[1]
  329. def p_arithmetic_operator(self, t):
  330. # The list of relations.
  331. """
  332. arithmetic : MOD
  333. | DIV
  334. | MULT
  335. | ADD
  336. | SUB
  337. """
  338. t[0] = t[1]
  339. ###############################################################################
  340. if __name__ == "__main__":
  341. import doctest
  342. doctest.testmod()