source: coopr.pyomo/trunk/coopr/pyomo/data/parse_datacmds.py @ 2285

Last change on this file since 2285 was 2285, checked in by wehart, 10 years ago

Working through more examples of the 'import' command.

File size: 8.1 KB
Line 
1
2#  _________________________________________________________________________
3#
4#  Coopr: A COmmon Optimization Python Repository
5#  Copyright (c) 2008 Sandia Corporation.
6#  This software is distributed under the BSD License.
7#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8#  the U.S. Government retains certain rights in this software.
9#  For more information, see the Coopr README.txt file.
10#  _________________________________________________________________________
11
12__all__ = ['parse_data_commands']
13
14import re
15import os
16import ply.lex as lex
17import ply.yacc as yacc
18from pyutilib.misc import flatten
19from pyutilib.ply import t_newline, t_ignore, _find_column, p_error, ply_init
20
21
22## -----------------------------------------------------------
23##
24## Lexer definitions for tokenizing the input
25##
26## -----------------------------------------------------------
27
28_parse_info = None
29debugging = False
30
31reserved = {
32    'data' : 'DATA',
33    'set' : 'SET',
34    'param' : 'PARAM',
35    'end' : 'END',
36    'import' : 'IMPORT',
37    'include' : 'INCLUDE',
38}
39
40# Token names
41tokens = [
42    "COMMA",
43#    "LBRACE",
44#    "RBRACE",
45#    "NUMBER",
46    "SEMICOLON",
47    "COLON",
48    "COLONEQ",
49    "LBRACKET",
50    "RBRACKET",
51    "LPAREN",
52    "RPAREN",
53#    "RANGE",
54    "WORD",
55    "STRING",
56    "QUOTEDSTRING",
57    "FILENAME",
58    "EQ",
59    "TR",
60    "NONWORD",
61] + reserved.values()
62
63# Regular expression rules
64t_COMMA     = r","
65t_LBRACKET  = r"\["
66t_RBRACKET  = r"\]"
67#t_NUMBER    = r"[0-9]+(\.[0-9]+){0,1}"
68t_SEMICOLON = r";"
69t_COLON     = r":"
70t_COLONEQ   = r":="
71t_EQ        = r"="
72t_TR        = r"\(tr\)"
73#t_LT        = r"<"
74#t_GT        = r">"
75#t_LBRACE    = r"{"
76#t_RBRACE    = r"}"
77t_LPAREN    = r"\("
78t_RPAREN    = r"\)"
79
80# Discard comments
81def t_COMMENT(t):
82    r'\#[^\n]*'
83    #global _comment_list
84    #_comment_list.append(t.value)
85
86def t_WORD(t):
87    r'[a-zA-Z_0-9][a-zA-Z_0-9\.]*'
88    t.type = reserved.get(t.value,'WORD')    # Check for reserved words
89    return t
90
91def t_STRING(t):
92    r'[a-zA-Z_0-9\.+\-]+'
93    t.type = reserved.get(t.value,'STRING')    # Check for reserved words
94    return t
95
96def t_QUOTEDSTRING(t):
97    r'"([^"]|\"\")*"|\'([^\']|\'\')*\''
98    t.type = reserved.get(t.value,'QUOTEDSTRING')    # Check for reserved words
99    return t
100
101def t_FILENAME(t):
102    r'[a-zA-Z_0-9\./\\]*(/|\\)[a-zA-Z_0-9\./\\]*'
103    t.type = reserved.get(t.value,'FILENAME')    # Check for reserved words
104    return t
105
106t_NONWORD   = r"[^\.A-Za-z0-9,;:<>\(\)\#{}\[\] \n\t\r]+"
107
108# Error handling rule
109def t_error(t):             #pragma:nocover
110    raise IOError, "Illegal character '%s'" % t.value[0]
111    t.lexer.skip(1)
112
113
114## -----------------------------------------------------------
115##
116## Yacc grammar for data commands
117##
118## -----------------------------------------------------------
119
120def p_expr(p):
121    '''expr : statements
122            | '''
123
124def p_statements(p):
125    '''statements : statement statements
126                  | statement '''
127
128def p_statement(p):
129    '''statement : SET WORD COLONEQ setdecl SEMICOLON
130                 | SET WORD COLONEQ SEMICOLON
131                 | SET WORD COLON items COLONEQ setdecl SEMICOLON
132                 | SET WORD COLON items COLONEQ SEMICOLON
133                 | SET indexed_word COLONEQ setdecl SEMICOLON
134                 | SET indexed_word COLONEQ SEMICOLON
135                 | PARAM items COLONEQ paramdecl SEMICOLON
136                 | IMPORT importdecl SEMICOLON
137                 | INCLUDE WORD SEMICOLON
138                 | INCLUDE QUOTEDSTRING SEMICOLON
139                 | DATA SEMICOLON
140                 | END SEMICOLON
141    '''
142    global _parse_info
143    #print "STATEMENT",len(p), p[1:]
144    if p[1] in ['set','param']:
145        _parse_info.append( flatten(p[1:-1]) )
146    elif p[1] in ['include']:
147        _parse_info.append( p[1:-1] )
148    elif p[1] in ['import']:
149        _parse_info.append( [p[1]]+ p[2] )
150        #_parse_info.append( [p[1], p[2][0], p[1:-1] )
151
152def p_setdecl(p):
153    '''setdecl : items'''
154    p[0] = p[1]
155
156def p_paramdecl(p):
157    '''paramdecl : items'''
158    p[0] = p[1]
159
160def p_importdecl(p):
161    '''importdecl : filename import_options
162                  | filename
163                  | filename import_options COLON indices variable_options
164                  | filename COLON indices variable_options
165                  | filename import_options COLON variable_options
166                  | filename COLON variable_options
167    '''
168    tmp = {'filename':p[1]}
169    if len(p) == 2:
170        p[0] = [tmp, [], {}]
171    elif len(p) == 3:
172        tmp.update(p[2])
173        p[0] = [tmp, [], {}]
174    elif len(p) == 4:
175        p[0] = [tmp, [], p[3]]
176    elif len(p) == 5:
177        if p[2] == ':':
178            p[0] = [tmp, p[3], p[4]]
179        else:
180            p[0] = [tmp, [], p[4]]
181    elif len(p) == 6:
182        tmp.update(p[2])
183        p[0] = [tmp, p[4], p[5]]
184    else:
185        raise IOError, "Unexpected condition"
186
187def p_import_options(p):
188    '''import_options : WORD EQ STRING import_options
189                      | WORD EQ QUOTEDSTRING import_options
190                      | WORD EQ STRING
191                      | WORD EQ QUOTEDSTRING
192    '''
193    tmp = {p[1]:p[3]}
194    if len(p) == 4:
195        p[0] = tmp
196    else:
197        tmp.update(p[4])
198        p[0] = tmp
199
200def p_variable_options(p):
201    '''variable_options : variable variable_options
202                        | variable
203    '''
204    if len(p) == 2:
205        p[0] = p[1]
206    else:
207        p[1].update(p[2])
208        p[0] = p[1]
209
210def p_variable(p):
211    '''variable : WORD
212                | WORD COLON WORD
213                | WORD COLON WORD index_list
214    '''
215    if len(p) == 2:
216        p[0] = {p[1]:[p[1]]}
217    elif len(p) == 4:
218        p[0] = {p[1]:[p[3]]}
219    else:
220        p[0] = {p[1]:[p[3]]+p[4]}
221
222def p_indices(p):
223    '''indices : LBRACKET WORD index_list RBRACKET
224               | LBRACKET WORD RBRACKET
225    '''
226    if len(p) == 5:
227        p[0] = [p[2]] + p[3]
228    else:
229        p[0] = [p[2]]
230
231def p_index_list(p):
232    '''index_list : COMMA WORD index_list
233                  | COMMA WORD
234    '''
235    if len(p) == 4:
236        p[0] = [p[2]]+p[3]
237    else:
238        p[0] = [p[2]]
239
240def p_indexed_word(p):
241    '''indexed_word : WORD LBRACKET WORD index_list RBRACKET
242                    | WORD LBRACKET WORD RBRACKET
243    '''
244    if len(p) == 6:
245        p[0] = p[1]+p[2]+",".join([p[3]]+p[4])+p[5]
246    else:
247        p[0] = p[1]+p[2]+p[3]+p[4]
248
249def p_items(p):
250    '''items : item items
251             | item'''
252    if len(p) == 2:
253        p[0] = [p[1]]
254    else:
255        p[0] = [p[1]] + p[2]
256
257def p_item(p):
258    '''item : WORD
259            | NONWORD
260            | STRING
261            | QUOTEDSTRING
262            | COMMA
263            | COLON
264            | LBRACKET
265            | RBRACKET
266            | TR
267            | LPAREN
268            | RPAREN
269    '''
270    p[0] = p[1]
271
272def p_filename(p):
273    '''filename : WORD
274                | STRING
275                | QUOTEDSTRING
276                | FILENAME
277    '''
278    p[0] = p[1]
279
280#
281# The function that performs the parsing
282#
283def parse_data_commands(data=None, filename=None, debug=0):
284    global debugging
285    #
286    # Always remove the parser.out file, which is generated to create debugging
287    #
288    if os.path.exists("parser.out"):        #pragma:nocover
289       os.remove("parser.out")
290    if debug > 0:                           #pragma:nocover
291        #
292        # Remove the parsetab.py* files.  These apparently need to be removed
293        # to ensure the creation of a parser.out file.
294        #
295        if os.path.exists("parsetab.py"):
296           os.remove("parsetab.py")
297        if os.path.exists("parsetab.pyc"):
298           os.remove("parsetab.pyc")
299        debugging=True
300    #
301    # Build lexer
302    #
303    lex.lex()
304    #
305    # Initialize parse object
306    #
307    global _parse_info
308    _parse_info = []
309    #
310    # Build yaccer
311    #
312    yacc.yacc(debug=debug)
313    #
314    # Parse the file
315    #
316    global _parsedata
317    if not data is None:
318        _parsedata=data
319        ply_init(_parsedata)
320        yacc.parse(data,debug=debug)
321    elif not filename is None:
322        f = open(filename)
323        data = f.read()
324        f.close()
325        _parsedata=data
326        ply_init(_parsedata)
327        yacc.parse(data, debug=debug)
328    else:
329        _parse_info = None
330    #
331    # Disable parsing I/O
332    #
333    debugging=False
334    return _parse_info
335
Note: See TracBrowser for help on using the repository browser.