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

Last change on this file since 2293 was 2293, checked in by wehart, 11 years ago

Bug fix for dealing with MS Windows filenames.

File size: 8.7 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 WORD EQ indices variable_options
164                  | filename COLON WORD EQ indices variable_options
165                  | filename import_options COLON indices variable_options
166                  | filename COLON indices variable_options
167                  | filename import_options COLON variable_options
168                  | filename COLON variable_options
169    '''
170    tmp = {'filename':p[1]}
171    if len(p) == 2:
172        p[0] = [tmp, (None,[]), {}]
173    elif len(p) == 3:
174        tmp.update(p[2])
175        p[0] = [tmp, (None,[]), {}]
176    elif len(p) == 4:
177        p[0] = [tmp, (None,[]), p[3]]
178    elif len(p) == 5:
179        if p[2] == ':':
180            p[0] = [tmp, (None,p[3]), p[4]]
181        else:
182            tmp.update(p[2])
183            p[0] = [tmp, (None,[]), p[4]]
184    elif len(p) == 6:
185        tmp.update(p[2])
186        p[0] = [tmp, (None,p[4]), p[5]]
187    elif len(p) == 7:
188        p[0] = [tmp, (p[3],p[5]), p[6]]
189    elif len(p) == 8:
190        tmp.update(p[2])
191        p[0] = [tmp, (p[4],p[6]), p[7]]
192    else:
193        raise IOError, "Unexpected condition"
194
195def p_import_options(p):
196    '''import_options : WORD EQ STRING import_options
197                      | WORD EQ STRING
198                      | WORD EQ QUOTEDSTRING import_options
199                      | WORD EQ QUOTEDSTRING
200                      | WORD EQ WORD import_options
201                      | WORD EQ WORD
202                      | WORD EQ PARAM import_options
203                      | WORD EQ PARAM
204                      | WORD EQ SET import_options
205                      | WORD EQ SET
206    '''
207    tmp = {p[1]:p[3]}
208    if len(p) == 4:
209        p[0] = tmp
210    else:
211        tmp.update(p[4])
212        p[0] = tmp
213
214def p_variable_options(p):
215    '''variable_options : variable variable_options
216                        | variable
217    '''
218    if len(p) == 2:
219        p[0] = p[1]
220    else:
221        p[1].update(p[2])
222        p[0] = p[1]
223
224def p_variable(p):
225    '''variable : WORD
226                | WORD EQ WORD
227    '''
228    if len(p) == 2:
229        p[0] = {p[1]:p[1]}
230    else:
231        p[0] = {p[3]:p[1]}
232
233def p_indices(p):
234    '''indices : LBRACKET WORD index_list RBRACKET
235               | LBRACKET WORD RBRACKET
236    '''
237    if len(p) == 5:
238        p[0] = [p[2]] + p[3]
239    else:
240        p[0] = [p[2]]
241
242def p_index_list(p):
243    '''index_list : COMMA WORD index_list
244                  | COMMA WORD
245    '''
246    if len(p) == 4:
247        p[0] = [p[2]]+p[3]
248    else:
249        p[0] = [p[2]]
250
251def p_indexed_word(p):
252    '''indexed_word : WORD LBRACKET WORD index_list RBRACKET
253                    | WORD LBRACKET WORD RBRACKET
254    '''
255    if len(p) == 6:
256        p[0] = p[1]+p[2]+",".join([p[3]]+p[4])+p[5]
257    else:
258        p[0] = p[1]+p[2]+p[3]+p[4]
259
260def p_items(p):
261    '''items : item items
262             | item'''
263    if len(p) == 2:
264        p[0] = [p[1]]
265    else:
266        p[0] = [p[1]] + p[2]
267
268def p_item(p):
269    '''item : WORD
270            | NONWORD
271            | STRING
272            | QUOTEDSTRING
273            | COMMA
274            | COLON
275            | LBRACKET
276            | RBRACKET
277            | TR
278            | LPAREN
279            | RPAREN
280    '''
281    p[0] = p[1]
282
283def p_filename(p):
284    '''filename : WORD
285                | STRING
286                | QUOTEDSTRING
287                | FILENAME
288                | WORD COLON FILENAME
289    '''
290    if len(p) == 2:
291        p[0] = p[1]
292    else:
293        p[0] = p[1]+p[2]+p[3]
294
295#
296# The function that performs the parsing
297#
298def parse_data_commands(data=None, filename=None, debug=0):
299    global debugging
300    #
301    # Always remove the parser.out file, which is generated to create debugging
302    #
303    if os.path.exists("parser.out"):        #pragma:nocover
304       os.remove("parser.out")
305    if debug > 0:                           #pragma:nocover
306        #
307        # Remove the parsetab.py* files.  These apparently need to be removed
308        # to ensure the creation of a parser.out file.
309        #
310        if os.path.exists("parsetab.py"):
311           os.remove("parsetab.py")
312        if os.path.exists("parsetab.pyc"):
313           os.remove("parsetab.pyc")
314        debugging=True
315    #
316    # Build lexer
317    #
318    lex.lex()
319    #
320    # Initialize parse object
321    #
322    global _parse_info
323    _parse_info = []
324    #
325    # Build yaccer
326    #
327    yacc.yacc(debug=debug)
328    #
329    # Parse the file
330    #
331    global _parsedata
332    if not data is None:
333        _parsedata=data
334        ply_init(_parsedata)
335        yacc.parse(data,debug=debug)
336    elif not filename is None:
337        f = open(filename)
338        data = f.read()
339        f.close()
340        _parsedata=data
341        ply_init(_parsedata)
342        yacc.parse(data, debug=debug)
343    else:
344        _parse_info = None
345    #
346    # Disable parsing I/O
347    #
348    debugging=False
349    return _parse_info
350
Note: See TracBrowser for help on using the repository browser.