temporal_raster_operator.py 11 KB

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