"""@package grass.temporal
Temporal operator evaluation with PLY
(C) 2013 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.
:authors: Thomas Leppelt and Soeren Gebbert
.. code-block:: python
>>> p = TemporalOperatorParser()
>>> expression = "{equal| during}"
>>> p.parse(expression, optype = 'relation')
>>> print(p.relations, p.temporal, p.function)
(['equal', 'during'], None, None)
>>> p = TemporalOperatorParser()
>>> expression = "{contains | starts}"
>>> p.parse(expression)
>>> print(p.relations, p.temporal, p.function)
(['contains', 'starts'], None, None)
>>> p = TemporalOperatorParser()
>>> expression = "{&&, during}"
>>> p.parse(expression, optype = 'boolean')
>>> print(p.relations, p.temporal, p.function,p.aggregate)
(['during'], 'l', '&&', '&')
>>> p = TemporalOperatorParser()
>>> expression = "{||, equal | during}"
>>> p.parse(expression, optype = 'boolean')
>>> print(p.relations, p.temporal, p.function,p.aggregate)
(['equal', 'during'], 'l', '||', '|')
>>> p = TemporalOperatorParser()
>>> expression = "{||, equal | during, &}"
>>> p.parse(expression, optype = 'boolean')
>>> print(p.relations, p.temporal, p.function,p.aggregate)
(['equal', 'during'], 'l', '||', '&')
>>> p = TemporalOperatorParser()
>>> expression = "{&&, during, |}"
>>> p.parse(expression, optype = 'boolean')
>>> print(p.relations, p.temporal, p.function,p.aggregate)
(['during'], 'l', '&&', '|')
>>> p = TemporalOperatorParser()
>>> expression = "{&&, during, |, r}"
>>> p.parse(expression, optype = 'boolean')
>>> print(p.relations, p.temporal, p.function,p.aggregate)
(['during'], 'r', '&&', '|')
>>> p = TemporalOperatorParser()
>>> expression = "{&&, during, u}"
>>> p.parse(expression, optype = 'boolean')
>>> print(p.relations, p.temporal, p.function,p.aggregate)
(['during'], 'u', '&&', '&')
>>> p = TemporalOperatorParser()
>>> expression = "{:, during, r}"
>>> p.parse(expression, optype = 'select')
>>> print(p.relations, p.temporal, p.function)
(['during'], 'r', ':')
>>> p = TemporalOperatorParser()
>>> expression = "{!:, equal | contains, d}"
>>> p.parse(expression, optype = 'select')
>>> print(p.relations, p.temporal, p.function)
(['equal', 'contains'], 'd', '!:')
>>> p = TemporalOperatorParser()
>>> expression = "{#, during, r}"
>>> p.parse(expression, optype = 'hash')
>>> print(p.relations, p.temporal, p.function)
(['during'], 'r', '#')
>>> p = TemporalOperatorParser()
>>> expression = "{#, equal | contains}"
>>> p.parse(expression, optype = 'hash')
>>> print(p.relations, p.temporal, p.function)
(['equal', 'contains'], 'l', '#')
>>> p = TemporalOperatorParser()
>>> expression = "{+, during, r}"
>>> p.parse(expression, optype = 'raster')
>>> print(p.relations, p.temporal, p.function)
(['during'], 'r', '+')
>>> p = TemporalOperatorParser()
>>> expression = "{/, equal | contains}"
>>> p.parse(expression, optype = 'raster')
>>> print(p.relations, p.temporal, p.function)
(['equal', 'contains'], 'l', '/')
>>> p = TemporalOperatorParser()
>>> expression = "{+, equal | contains,intersect}"
>>> p.parse(expression, optype = 'raster')
>>> print(p.relations, p.temporal, p.function)
(['equal', 'contains'], 'i', '+')
>>> p = TemporalOperatorParser()
>>> expression = "{*, contains,disjoint}"
>>> p.parse(expression, optype = 'raster')
>>> print(p.relations, p.temporal, p.function)
(['contains'], 'd', '*')
>>> p = TemporalOperatorParser()
>>> expression = "{~, equal,left}"
>>> p.parse(expression, optype = 'overlay')
>>> print(p.relations, p.temporal, p.function)
(['equal'], 'l', '~')
>>> p = TemporalOperatorParser()
>>> expression = "{^, over,right}"
>>> p.parse(expression, optype = 'overlay')
>>> print(p.relations, p.temporal, p.function)
(['overlaps', 'overlapped'], 'r', '^')
"""
try:
import ply.lex as lex
import ply.yacc as yacc
except:
pass
[docs]class TemporalOperatorLexer(object):
"""Lexical analyzer for the GRASS GIS temporal operator"""
# Functions that defines topological relations.
relations = {
'equal' : "EQUAL",
'follows' : "FOLLOWS",
'precedes' : "PRECEDES",
'overlaps' : "OVERLAPS",
'overlapped' : "OVERLAPPED",
'during' : "DURING",
'starts' : "STARTS",
'finishes' : "FINISHES",
'contains' : "CONTAINS",
'started' : "STARTED",
'finished' : "FINISHED",
'over' : "OVER"
}
# This is the list of token names.
tokens = (
'COMMA',
'LEFTREF',
'RIGHTREF',
'UNION',
'DISJOINT',
'INTERSECT',
'HASH',
'OR',
'AND',
'DISOR',
'XOR',
'NOT',
'MOD',
'DIV',
'MULT',
'ADD',
'SUB',
'T_SELECT',
'T_NOT_SELECT',
'CLPAREN',
'CRPAREN',
)
# Build the token list
tokens = tokens + tuple(relations.values())
# Regular expression rules for simple tokens
t_T_SELECT = r':'
t_T_NOT_SELECT = r'!:'
t_COMMA = r','
t_LEFTREF = '^[l|left]'
t_RIGHTREF ='^[r|right]'
t_UNION = '^[u|union]'
t_DISJOINT = '^[d|disjoint]'
t_INTERSECT = '^[i|intersect]'
t_HASH = r'\#'
t_OR = r'[\|]'
t_AND = r'[&]'
t_DISOR = r'\+'
t_XOR = r'\^'
t_NOT = r'\~'
t_MOD = r'[\%]'
t_DIV = r'[\/]'
t_MULT = r'[\*]'
t_ADD = r'[\+]'
t_SUB = r'[-]'
t_CLPAREN = r'\{'
t_CRPAREN = r'\}'
# These are the things that should be ignored.
t_ignore = ' \t'
# Track line numbers.
[docs] def t_NAME(self, t):
r'[a-zA-Z_][a-zA-Z_0-9]*'
self.temporal_symbol(t)
return t
# Parse symbols
[docs] def temporal_symbol(self, t):
# Check for reserved words
if t.value in TemporalOperatorLexer.relations.keys():
t.type = TemporalOperatorLexer.relations.get(t.value)
elif t.value == 'l' or t.value == 'left':
t.value = 'l'
t.type = 'LEFTREF'
elif t.value == 'r' or t.value == 'right':
t.value = 'r'
t.type = 'RIGHTREF'
elif t.value == 'u' or t.value == 'union':
t.value = 'u'
t.type = 'UNION'
elif t.value == 'd' or t.value == 'disjoint':
t.value = 'd'
t.type = 'DISJOINT'
elif t.value == 'i' or t.value == 'intersect':
t.value = 'i'
t.type = 'INTERSECT'
#else:
# t.type = 'NAME'
return(t)
# Handle errors.
[docs] def t_error(self, t):
raise SyntaxError("syntax error on line %d near '%s'" %
(t.lineno, t.value))
# Build the lexer
[docs] def test(self,data):
self.name_list = {}
print(data)
self.lexer.input(data)
while True:
tok = self.lexer.token()
if not tok: break
print tok
###############################################################################
[docs]class TemporalOperatorParser(object):
"""The temporal operator class"""
def __init__(self):
self.lexer = TemporalOperatorLexer()
self.lexer.build()
self.parser = yacc.yacc(module=self)
self.relations = None
self.temporal = None
self.function = None
self.aggregate = None
[docs] def parse(self, expression, optype = 'relation'):
self.optype = optype
self.parser.parse(expression)
# The parameter optype can be of type: select {:, during, r}, boolean{&&, contains, |},
# raster{*, equal, |}, vector {|, starts, &},
# hash{#, during, l} or relation {during}.
# Error rule for syntax errors.
[docs] def p_error(self, t):
raise SyntaxError("Unexpected syntax error")
# Get the tokens from the lexer class
tokens = TemporalOperatorLexer.tokens
[docs] def p_relation_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN relation CRPAREN
| CLPAREN relationlist CRPAREN
"""
# Check for correct type.
if not self.optype == 'relation':
raise SyntaxError("invalid syntax")
else:
# Set three operator components.
if isinstance(t[2], list):
self.relations = t[2]
else:
self.relations = [t[2]]
self.temporal = None
self.function = None
t[0] = t[2]
[docs] def p_relation_bool_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN OR OR COMMA relation CRPAREN
| CLPAREN AND AND COMMA relation CRPAREN
| CLPAREN OR OR COMMA relationlist CRPAREN
| CLPAREN AND AND COMMA relationlist CRPAREN
"""
if not self.optype == 'boolean':
raise SyntaxError("invalid syntax")
else:
# Set three operator components.
if isinstance(t[5], list):
self.relations = t[5]
else:
self.relations = [t[5]]
self.temporal = "l"
self.function = t[2] + t[3]
self.aggregate = t[2]
t[0] = t[2]
[docs] def p_relation_bool_combi_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN OR OR COMMA relation COMMA OR CRPAREN
| CLPAREN OR OR COMMA relation COMMA AND CRPAREN
| CLPAREN AND AND COMMA relation COMMA OR CRPAREN
| CLPAREN AND AND COMMA relation COMMA AND CRPAREN
| CLPAREN OR OR COMMA relationlist COMMA OR CRPAREN
| CLPAREN OR OR COMMA relationlist COMMA AND CRPAREN
| CLPAREN AND AND COMMA relationlist COMMA OR CRPAREN
| CLPAREN AND AND COMMA relationlist COMMA AND CRPAREN
"""
if not self.optype == 'boolean':
raise SyntaxError("invalid syntax")
else:
# Set three operator components.
if isinstance(t[5], list):
self.relations = t[5]
else:
self.relations = [t[5]]
self.temporal = "l"
self.function = t[2] + t[3]
self.aggregate = t[7]
t[0] = t[2]
[docs] def p_relation_bool_combi_operator2(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN OR OR COMMA relation COMMA temporal CRPAREN
| CLPAREN AND AND COMMA relation COMMA temporal CRPAREN
| CLPAREN OR OR COMMA relationlist COMMA temporal CRPAREN
| CLPAREN AND AND COMMA relationlist COMMA temporal CRPAREN
"""
if not self.optype == 'boolean':
raise SyntaxError("invalid syntax")
else:
# Set three operator components.
if isinstance(t[5], list):
self.relations = t[5]
else:
self.relations = [t[5]]
self.temporal = t[7]
self.function = t[2] + t[3]
self.aggregate = t[2]
t[0] = t[2]
[docs] def p_relation_bool_combi_operator3(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN OR OR COMMA relation COMMA OR COMMA temporal CRPAREN
| CLPAREN OR OR COMMA relation COMMA AND COMMA temporal CRPAREN
| CLPAREN AND AND COMMA relation COMMA OR COMMA temporal CRPAREN
| CLPAREN AND AND COMMA relation COMMA AND COMMA temporal CRPAREN
| CLPAREN OR OR COMMA relationlist COMMA OR COMMA temporal CRPAREN
| CLPAREN OR OR COMMA relationlist COMMA AND COMMA temporal CRPAREN
| CLPAREN AND AND COMMA relationlist COMMA OR COMMA temporal CRPAREN
| CLPAREN AND AND COMMA relationlist COMMA AND COMMA temporal CRPAREN
"""
if not self.optype == 'boolean':
raise SyntaxError("invalid syntax")
else:
# Set three operator components.
if isinstance(t[5], list):
self.relations = t[5]
else:
self.relations = [t[5]]
self.temporal = t[9]
self.function = t[2] + t[3]
self.aggregate = t[7]
t[0] = t[2]
[docs] def p_select_relation_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN select CRPAREN
| CLPAREN select COMMA relation CRPAREN
| CLPAREN select COMMA relationlist CRPAREN
| CLPAREN select COMMA relation COMMA temporal CRPAREN
| CLPAREN select COMMA relationlist COMMA temporal CRPAREN
"""
if not self.optype == 'select':
raise SyntaxError("invalid syntax")
else:
if len(t) == 4:
# Set three operator components.
self.relations = ['equal']
self.temporal = "l"
self.function = t[2]
elif len(t) == 5:
self.relations = ['equal']
self.temporal = t[3]
self.function = t[2]
elif len(t) == 6:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = "l"
self.function = t[2]
elif len(t) == 8:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = t[6]
self.function = t[2]
t[0] = t[2]
[docs] def p_hash_relation_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN HASH CRPAREN
| CLPAREN HASH COMMA relation CRPAREN
| CLPAREN HASH COMMA relationlist CRPAREN
| CLPAREN HASH COMMA relation COMMA temporal CRPAREN
| CLPAREN HASH COMMA relationlist COMMA temporal CRPAREN
"""
if not self.optype == 'hash':
raise SyntaxError("invalid syntax")
else:
if len(t) == 4:
# Set three operator components.
self.relations = ['equal']
self.temporal = "l"
self.function = t[2]
elif len(t) == 5:
self.relations = ['equal']
self.temporal = t[3]
self.function = t[2]
elif len(t) == 6:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = "l"
self.function = t[2]
elif len(t) == 8:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = t[6]
self.function = t[2]
t[0] = t[2]
[docs] def p_raster_relation_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN arithmetic CRPAREN
| CLPAREN arithmetic COMMA relation CRPAREN
| CLPAREN arithmetic COMMA relationlist CRPAREN
| CLPAREN arithmetic COMMA relation COMMA temporal CRPAREN
| CLPAREN arithmetic COMMA relationlist COMMA temporal CRPAREN
"""
if not self.optype == 'raster':
raise SyntaxError("invalid syntax")
else:
if len(t) == 4:
# Set three operator components.
self.relations = ['equal']
self.temporal = "l"
self.function = t[2]
elif len(t) == 5:
self.relations = ['equal']
self.temporal = t[3]
self.function = t[2]
elif len(t) == 6:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = "l"
self.function = t[2]
elif len(t) == 8:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = t[6]
self.function = t[2]
t[0] = t[2]
[docs] def p_overlay_relation_operator(self, t):
# The expression should always return a list of maps.
"""
operator : CLPAREN overlay CRPAREN
| CLPAREN overlay COMMA relation CRPAREN
| CLPAREN overlay COMMA relationlist CRPAREN
| CLPAREN overlay COMMA relation COMMA temporal CRPAREN
| CLPAREN overlay COMMA relationlist COMMA temporal CRPAREN
"""
if not self.optype == 'overlay':
raise SyntaxError("invalid syntax")
else:
if len(t) == 4:
# Set three operator components.
self.relations = ['equal']
self.temporal = "l"
self.function = t[2]
elif len(t) == 5:
self.relations = ['equal']
self.temporal = t[3]
self.function = t[2]
elif len(t) == 6:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = "l"
self.function = t[2]
elif len(t) == 8:
if isinstance(t[4], list):
self.relations = t[4]
else:
self.relations = [t[4]]
self.temporal = t[6]
self.function = t[2]
t[0] = t[2]
[docs] def p_relation(self, t):
# The list of relations.
"""
relation : EQUAL
| FOLLOWS
| PRECEDES
| OVERLAPS
| OVERLAPPED
| DURING
| STARTS
| FINISHES
| CONTAINS
| STARTED
| FINISHED
"""
t[0] = t[1]
[docs] def p_over(self, t):
# The list of relations.
"""
relation : OVER
"""
over_list = ["overlaps", "overlapped"]
t[0] = over_list
[docs] def p_relationlist(self, t):
# The list of relations.
"""
relationlist : relation OR relation
| relation OR relationlist
"""
rel_list = []
rel_list.append(t[1])
if isinstance(t[3], list):
rel_list = rel_list + t[3]
else:
rel_list.append(t[3])
t[0] = rel_list
[docs] def p_temporal_operator(self, t):
# The list of relations.
"""
temporal : LEFTREF
| RIGHTREF
| UNION
| DISJOINT
| INTERSECT
"""
t[0] = t[1]
[docs] def p_select_operator(self, t):
# The list of relations.
"""
select : T_SELECT
| T_NOT_SELECT
"""
t[0] = t[1]
[docs] def p_arithmetic_operator(self, t):
# The list of relations.
"""
arithmetic : MOD
| DIV
| MULT
| ADD
| SUB
"""
t[0] = t[1]
[docs] def p_overlay_operator(self, t):
# The list of relations.
"""
overlay : AND
| OR
| XOR
| DISOR
| NOT
"""
t[0] = t[1]
###############################################################################
if __name__ == "__main__":
import doctest
doctest.testmod()
Help Index | Topics Index | Keywords Index | Full Index
© 2003-2018 GRASS Development Team, GRASS GIS 7.0.7svn Reference Manual