blob: c246baf9908b5811ec3b3a7f8ac92e02dbeec97b [file] [log] [blame]
Sapan Bhatia64c72512017-06-23 02:32:45 -07001__author__ = "Sapan Bhatia"
2
3__copyright__ = "Copyright (C) 2017 Open Networking Lab"
4__version__ = "1.0"
5
6import ply.lex as lex
7import ply.yacc as yacc
8
9from helpers import LexHelper, LU
10
Sapan Bhatia9c579722018-01-12 13:45:09 -050011class FOLParsingError(Exception):
12 def __init__(self, message, error_range):
13 super(FOLParsingError, self).__init__(message)
14 self.error_range = error_range
15
Sapan Bhatia64c72512017-06-23 02:32:45 -070016class FOLLexer(object):
Sapan Bhatiacee04022017-07-20 02:12:43 -040017 keywords = ('forall', 'exists', 'True', 'False', 'not', 'in')
Sapan Bhatia64c72512017-06-23 02:32:45 -070018
Sapan Bhatia99669732017-07-25 19:19:14 -040019 tokens = ['STRING_LITERAL', 'NUM', 'ESCAPE', 'COLON', 'IMPLIES', 'OR', 'AND', 'LPAREN', 'RPAREN', 'EQUALS', 'SYMBOL', 'LT', 'RT', 'STAR'] + [k.upper() for k in keywords]
Sapan Bhatia64c72512017-06-23 02:32:45 -070020 # literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
21
22 t_ignore_LINE_COMMENT = '//.*'
23 t_COLON = '\\:'
24 t_IMPLIES = '\\-\\>'
25 t_OR = '\\|'
Sapan Bhatia99669732017-07-25 19:19:14 -040026 t_STAR = '\\*'
Sapan Bhatia64c72512017-06-23 02:32:45 -070027 t_LT = '\\<'
28 t_RT = '\\>'
29 t_AND = '\\&'
30 t_LPAREN = '\\('
31 t_RPAREN = '\\)'
Sapan Bhatiafc1278c2017-07-17 12:57:13 -040032 t_NUM = r'[+-]?\d+(\.\d+)?'
33 t_STRING_LITERAL = r'\"([^\\\n]|(\\.))*?\"'
Sapan Bhatia64c72512017-06-23 02:32:45 -070034
35 t_EQUALS = '\\='
36
37 literals = '()+-*/=?:,.^|&~!=[]{};<>@%'
38
39 t_ignore = ' \t\f'
40
41 def t_newline(self, t):
42 r'\n+'
43 t.lexer.lineno += len(t.value)
44
45 def t_newline2(self, t):
46 r'(\r\n)+'
47 t.lexer.lineno += len(t.value) / 2
48
Sapan Bhatia9c579722018-01-12 13:45:09 -050049 def t_ESCAPE(self, t):
50 r'{{ (.|\n)*? }}'
51 t.lexer.lineno += t.value.count('\n')
52 return t
Sapan Bhatia64c72512017-06-23 02:32:45 -070053
54 def t_BLOCK_COMMENT(self, t):
55 r'/\*(.|\n)*?\*/'
56 t.lexer.lineno += t.value.count('\n')
57
58 def t_SYMBOL(self, t):
Sapan Bhatia99669732017-07-25 19:19:14 -040059 '[A-Za-z_$][\.A-Za-z0-9_+$]*(\(\))?'
Sapan Bhatia64c72512017-06-23 02:32:45 -070060 if t.value in FOLLexer.keywords:
61 t.type = t.value.upper()
62 return t
63
64 def t_error(self, t):
65 print("Illegal character '{}' ({}) in line {}".format(t.value[0], hex(ord(t.value[0])), t.lexer.lineno))
66 t.lexer.skip(1)
67
68
69
70class FOLParser(object):
71 tokens = FOLLexer.tokens
72 offset = 0
73 lh = LexHelper()
74
75 def setOffset(self, of):
76 self.offset = of
77 self.lh.offset = of
78
Sapan Bhatiafc1278c2017-07-17 12:57:13 -040079 def p_term_numeric_constant(self, p):
80 '''term : NUM'''
81 p[0] = p[1]
82
83 def p_term_string_constant(self, p):
84 '''term : STRING_LITERAL'''
85 p[0] = p[1]
86
87 def p_term_boolean_constant(self, p):
Sapan Bhatia64c72512017-06-23 02:32:45 -070088 '''term : FALSE
89 | TRUE'''
90 p[0] = p[1]
91
Sapan Bhatia99669732017-07-25 19:19:14 -040092 def p_term_policy_function(self, p):
93 '''term : STAR SYMBOL LPAREN SYMBOL RPAREN'''
94 p[0] = {'policy': [p[2], p[4]]}
95
Sapan Bhatia64c72512017-06-23 02:32:45 -070096 def p_fole_not(self, p):
97 '''fole : NOT fole'''
98 p[0] = {p[1]: p[2]}
99
100 def p_fole_term(self, p):
101 '''fole : term'''
102 p[0] = p[1]
103
104 def p_term_symbol(self, p):
105 '''term : SYMBOL'''
106 p[0] = p[1]
107
108 def p_term_python(self, p):
Sapan Bhatiab934f722017-07-15 08:42:19 -0400109 '''term : ESCAPE'''
Sapan Bhatiabc6268c2017-07-16 02:43:45 -0400110 p[0] = {'python': p[1].lstrip('{ ').rstrip(' }')}
Sapan Bhatia64c72512017-06-23 02:32:45 -0700111
112 def p_fole_group(self, p):
113 "fole : LPAREN fole RPAREN"
114 p[0] = p[2]
115
Sapan Bhatiacee04022017-07-20 02:12:43 -0400116 def p_fole_in(self, p):
117 "fole : term IN term"
118 p[0] = {'in': (p[1], p[3])}
119
Sapan Bhatia64c72512017-06-23 02:32:45 -0700120 def p_fole_equals(self, p):
121 "fole : term EQUALS term"
122 p[0] = {'=': (p[1], p[3])}
123
124 def p_fole_binary(self, p):
125 '''fole : fole AND fole
126 | fole OR fole
127 | fole IMPLIES fole'''
128 p[0] = {p[2]: [p[1], p[3]]}
129
130 def p_fole_quant(self, p):
131 '''fole : FORALL SYMBOL COLON fole
132 | EXISTS SYMBOL COLON fole'''
133 p[0] = {p[1]: [p[2], p[4]]}
134
Sapan Bhatia64c72512017-06-23 02:32:45 -0700135 def p_goal(self, p):
136 '''goal : LT fole RT'''
137 p[0] = p[2]
138
139 def p_error(self, p):
Sapan Bhatia9c579722018-01-12 13:45:09 -0500140 error = 'error: {}'.format(p)
141 raise FOLParsingError(error, (p.lineno,p.lexpos,len(p.value)))
Sapan Bhatia64c72512017-06-23 02:32:45 -0700142
Sapan Bhatia9c579722018-01-12 13:45:09 -0500143 precedence = (
144 ("right", "IMPLIES"),
145 ("left", "OR"),
146 ("left", "AND"),
147 ("right", "COLON"),
148 ("right", "NOT"),
149 ("right", "STAR"),
150 ("right", "ESCAPE"),
151 ("nonassoc", "EQUALS", "IN"))