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

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

Setting up 'import' tests for the other simple examples.
These seem to work, but the internal code is too ugly. I'm
going to clean that up next to help explain what is going on...

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