123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- """@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
- 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.
- def t_newline(self, t):
- r'\n+'
- t.lineno += len(t.value)
- def t_NAME(self, t):
- r'[a-zA-Z_][a-zA-Z_0-9]*'
- self.temporal_symbol(t)
- return t
- # Parse symbols
- 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.
- def t_error(self, t):
- raise SyntaxError("syntax error on line %d near '%s'" %
- (t.lineno, t.value))
- # Build the lexer
- def build(self,**kwargs):
- self.lexer = lex.lex(module=self, **kwargs)
- # Just for testing
- 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
- ###############################################################################
- 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
- 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.
- def p_error(self, t):
- raise SyntaxError("Unexpected syntax error")
- # Get the tokens from the lexer class
- tokens = TemporalOperatorLexer.tokens
-
- 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]
- 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]
- 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]
- 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]
-
- 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]
-
- 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]
- 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]
- 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]
- 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]
- 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]
- def p_over(self, t):
- # The list of relations.
- """
- relation : OVER
- """
- over_list = ["overlaps", "overlapped"]
- t[0] = over_list
- 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
- def p_temporal_operator(self, t):
- # The list of relations.
- """
- temporal : LEFTREF
- | RIGHTREF
- | UNION
- | DISJOINT
- | INTERSECT
- """
- t[0] = t[1]
- def p_select_operator(self, t):
- # The list of relations.
- """
- select : T_SELECT
- | T_NOT_SELECT
- """
- t[0] = t[1]
- def p_arithmetic_operator(self, t):
- # The list of relations.
- """
- arithmetic : MOD
- | DIV
- | MULT
- | ADD
- | SUB
- """
- t[0] = t[1]
- 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()
|